home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 24 / CU Amiga Magazine's Super CD-ROM 24 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-07].iso / CUCD / Utilities / vim-5.1 / src / screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-01  |  122.0 KB  |  5,063 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * screen.c: code for displaying on the screen
  11.  */
  12.  
  13. #include "vim.h"
  14.  
  15. /*
  16.  * The attributes that are actually active for writing to the screen.
  17.  */
  18. static int    screen_attr = 0;
  19.  
  20. /*
  21.  * Positioning the cursor is reduced by remembering the last position.
  22.  * Mostly used by windgoto() and screen_char().
  23.  */
  24. static int    screen_cur_row, screen_cur_col;    /* last known cursor position */
  25.  
  26. #ifdef EXTRA_SEARCH
  27. /*
  28.  * When highlighting matches for the last use search pattern:
  29.  * - search_hl_prog points to the regexp program for it
  30.  * - search_hl_attr contains the attributes to be used
  31.  * - search_hl_ic is the value for "reg_ic" for this search
  32.  */
  33. vim_regexp    *search_hl_prog = NULL;
  34. int        search_hl_attr;
  35. int        search_hl_ic;
  36. #endif
  37.  
  38. /*
  39.  * Flags for w_valid.
  40.  * These are suppose to be used only in screen.c.  From other files, use the
  41.  * functions that set or reset them.
  42.  *
  43.  * VALID_BOTLINE    VALID_BOTLINE_AP
  44.  *     on        on        w_botline valid
  45.  *     off        on        w_botline approximated
  46.  *     off        off        w_botline not valid
  47.  *     on        off        not possible
  48.  */
  49. #define VALID_WROW    0x01    /* w_wrow (window row) is valid */
  50. #define VALID_WCOL    0x02    /* w_wcol (window col) is valid */
  51. #define VALID_VIRTCOL    0x04    /* w_virtcol (file col) is valid */
  52. #define VALID_CHEIGHT    0x08    /* w_cline_height is valid */
  53. #define VALID_CROW    0x10    /* w_cline_row is valid */
  54. #define VALID_BOTLINE    0x20    /* w_botine and w_empty_rows are valid */
  55. #define VALID_BOTLINE_AP 0x40    /* w_botine is approximated */
  56.  
  57. /*
  58.  * Buffer for one screen line.
  59.  */
  60. static char_u *current_LinePointer;
  61.  
  62. static void win_update __ARGS((WIN *wp));
  63. static int win_line __ARGS((WIN *, linenr_t, int, int));
  64. #ifdef RIGHTLEFT
  65. static void screen_line __ARGS((int row, int endcol, int clear_rest, int rlflag));
  66. #define SCREEN_LINE(r, e, c, rl)    screen_line((r), (e), (c), (rl))
  67. #else
  68. static void screen_line __ARGS((int row, int endcol, int clear_rest));
  69. #define SCREEN_LINE(r, e, c, rl)    screen_line((r), (e), (c))
  70. #endif
  71. #ifdef EXTRA_SEARCH
  72. static void start_search_hl __ARGS((void));
  73. static void end_search_hl __ARGS((void));
  74. #endif
  75. static void screen_start_highlight __ARGS((int attr));
  76. static void comp_botline __ARGS((void));
  77. static void screen_char __ARGS((char_u *, int, int));
  78. static void screenclear2 __ARGS((void));
  79. static void lineclear __ARGS((char_u *p));
  80. static void check_cursor_moved __ARGS((WIN *wp));
  81. static void curs_rows __ARGS((int do_botline));
  82. static void validate_virtcol_win __ARGS((WIN *wp));
  83. static int screen_ins_lines __ARGS((int, int, int, int));
  84. static int highlight_status __ARGS((int *attr, int is_curwin));
  85. static void win_redr_ruler __ARGS((WIN *wp, int always));
  86. static void intro_message __ARGS((void));
  87.  
  88. /*
  89.  * update_screenline() - like update_screen() but only for cursor line
  90.  *
  91.  * Must only be called when something in the cursor line has changed (e.g.
  92.  * character inserted or deleted).
  93.  *
  94.  * Check if the size of the cursor line has changed since the last screen
  95.  * update.  If it did change, lines below the cursor will move up or down and
  96.  * we need to call the routine update_screen() to examine the entire screen.
  97.  */
  98.     void
  99. update_screenline()
  100. {
  101.     int        row;
  102.     int        old_cline_height;
  103.  
  104.     if (!screen_valid(TRUE))
  105.     return;
  106.  
  107.     if (must_redraw)            /* must redraw whole screen */
  108.     {
  109.     update_screen(must_redraw);
  110.     return;
  111.     }
  112.  
  113.     if (!redrawing())
  114.     {
  115.     redraw_later(NOT_VALID);    /* remember to update later */
  116.     return;
  117.     }
  118.  
  119.     /*
  120.      * If the screen has scrolled, or some lines after the cursor line have
  121.      * been invalidated, call update_screen().
  122.      */
  123.     if (curwin->w_lsize_valid <= curwin->w_cursor.lnum - curwin->w_topline ||
  124.                 curwin->w_lsize_lnum[0] != curwin->w_topline)
  125.     {
  126.     update_screen(VALID_TO_CURSCHAR);
  127.     return;
  128.     }
  129.  
  130.     /*
  131.      * Get the current height of the cursor line, as it is on the screen.
  132.      * w_lsize[] must be used here, since w_cline_height might already have
  133.      * been updated to the new height of the line in the buffer.
  134.      */
  135.     old_cline_height = curwin->w_lsize[curwin->w_cursor.lnum
  136.                               - curwin->w_topline];
  137.  
  138.     /*
  139.      * Check if the cursor line is still at the same position.    Be aware of
  140.      * the cursor having moved around, w_cline_row may be invalid, use the
  141.      * values from w_lsize[] by calling curs_rows().
  142.      */
  143.     check_cursor_moved(curwin);
  144.     if (!(curwin->w_valid & VALID_CROW))
  145.     curs_rows(FALSE);
  146. #ifdef EXTRA_SEARCH
  147.     start_search_hl();
  148. #endif
  149.  
  150.     /*
  151.      * w_virtcol needs to be valid.
  152.      */
  153.     validate_virtcol();
  154.     cursor_off();
  155.     row = win_line(curwin, curwin->w_cursor.lnum,
  156.         curwin->w_cline_row, curwin->w_height);
  157.  
  158.     display_hint = HINT_NONE;
  159. #ifdef EXTRA_SEARCH
  160.     end_search_hl();
  161. #endif
  162.  
  163.     if (row == curwin->w_height + 1)    /* line too long for window */
  164.     {
  165.     if (curwin->w_topline < curwin->w_cursor.lnum)
  166.     {
  167.         /*
  168.          * Window needs to be scrolled up to show the cursor line.
  169.          * We know w_botline was valid before the change, so it should now
  170.          * be one less.  This removes the need to recompute w_botline in
  171.          * update_topline().
  172.          */
  173.         --curwin->w_botline;
  174.         curwin->w_valid |= VALID_BOTLINE_AP;
  175.     }
  176.     update_topline();
  177.     update_screen(VALID_TO_CURSCHAR);
  178.     }
  179.     else if (!dollar_vcol)
  180.     {
  181.     /*
  182.      * If the cursor line changed size, delete or insert screen lines and
  183.      * redraw the rest of the window.
  184.      */
  185.     if (old_cline_height != curwin->w_cline_height)
  186.     {
  187.         if (curwin->w_cline_height < old_cline_height)
  188.         win_del_lines(curwin, row,
  189.               old_cline_height - curwin->w_cline_height, FALSE, TRUE);
  190.         else
  191.         win_ins_lines(curwin,
  192.                  curwin->w_cline_row + curwin->w_cline_height,
  193.               curwin->w_cline_height - old_cline_height, FALSE, TRUE);
  194.         update_screen(VALID_TO_CURSCHAR);
  195.     }
  196. #ifdef SYNTAX_HL
  197.     /*
  198.      * If syntax lost its sync, have to redraw the following lines.
  199.      */
  200.     else if (syntax_present(curbuf) && row < cmdline_row &&
  201.                   syntax_check_changed(curwin->w_cursor.lnum + 1))
  202.         update_screen(VALID_TO_CURSCHAR);
  203. #endif
  204.     else if (clear_cmdline || redraw_cmdline)
  205.         showmode();            /* clear cmdline, show mode and ruler */
  206.     }
  207. }
  208.  
  209. /*
  210.  * Redraw the current window later, with UpdateScreen(type).
  211.  * Set must_redraw only of not already set to a higher value.
  212.  * e.g. if must_redraw is CLEAR, type == NOT_VALID will do nothing.
  213.  */
  214.     void
  215. redraw_later(type)
  216.     int        type;
  217. {
  218.     if (curwin->w_redr_type < type)
  219.     curwin->w_redr_type = type;
  220.     if (must_redraw < type)    /* must_redraw is the maximum of all windows */
  221.     must_redraw = type;
  222. }
  223.  
  224. /*
  225.  * Mark all windows to be redrawn later.
  226.  */
  227.     void
  228. redraw_all_later(type)
  229.     int        type;
  230. {
  231.     WIN            *wp;
  232.  
  233.     for (wp = firstwin; wp; wp = wp->w_next)
  234.     if (wp->w_redr_type < type)
  235.         wp->w_redr_type = type;
  236.     redraw_later(type);
  237. }
  238.  
  239. /*
  240.  * Mark all windows that are editing the current buffer to be udpated later.
  241.  */
  242.     void
  243. redraw_curbuf_later(type)
  244.     int        type;
  245. {
  246.     WIN            *wp;
  247.  
  248.     for (wp = firstwin; wp; wp = wp->w_next)
  249.     if (wp->w_redr_type < type && wp->w_buffer == curbuf)
  250.         wp->w_redr_type = type;
  251.     redraw_later(type);
  252. }
  253.  
  254. /*
  255.  * update all windows that are editing the current buffer
  256.  */
  257.     void
  258. update_curbuf(type)
  259.     int        type;
  260. {
  261.     redraw_curbuf_later(type);
  262.     update_screen(type);
  263. }
  264.  
  265. /*
  266.  * update_screen()
  267.  *
  268.  * Based on the current value of curwin->w_topline, transfer a screenfull
  269.  * of stuff from Filemem to NextScreen, and update curwin->w_botline.
  270.  */
  271.  
  272.     void
  273. update_screen(type)
  274.     int            type;
  275. {
  276.     WIN            *wp;
  277.     static int        did_intro = FALSE;
  278.  
  279.     if (!screen_valid(TRUE))
  280.     return;
  281.  
  282.     dollar_vcol = 0;
  283.  
  284.     if (must_redraw)
  285.     {
  286.     if (type < must_redraw)        /* use maximal type */
  287.         type = must_redraw;
  288.     must_redraw = 0;
  289.     }
  290.  
  291.     if (curwin->w_lsize_valid == 0 && type < NOT_VALID)
  292.     type = NOT_VALID;
  293.  
  294.     if (!redrawing())
  295.     {
  296.     redraw_later(type);        /* remember type for next time */
  297.     curwin->w_redr_type = type;
  298.     curwin->w_lsize_valid = 0;    /* don't use w_lsize[] now */
  299.     return;
  300.     }
  301.  
  302.     /*
  303.      * if the screen was scrolled up when displaying a message, scroll it down
  304.      */
  305.     if (msg_scrolled)
  306.     {
  307.     clear_cmdline = TRUE;
  308.     if (msg_scrolled > Rows - 5)        /* clearing is faster */
  309.         type = CLEAR;
  310.     else if (type != CLEAR)
  311.     {
  312.         check_for_delay(FALSE);
  313.         if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows) == FAIL)
  314.         type = CLEAR;
  315.         win_rest_invalid(firstwin);        /* should do only first/last few */
  316.     }
  317.     msg_scrolled = 0;
  318.     need_wait_return = FALSE;
  319.     }
  320.  
  321.     /* reset cmdline_row now (may have been changed temporarily) */
  322.     compute_cmdrow();
  323.  
  324.     /* Check for changed highlighting */
  325.     if (need_highlight_changed)
  326.     highlight_changed();
  327.  
  328.     if (type == CLEAR)        /* first clear screen */
  329.     {
  330.     screenclear();        /* will reset clear_cmdline */
  331.     type = NOT_VALID;
  332.     }
  333.  
  334.     if (clear_cmdline)        /* first clear cmdline */
  335.     {
  336.     check_for_delay(FALSE);
  337.     msg_row = cmdline_row;
  338.     msg_col = 0;
  339.     msg_clr_eos();        /* will reset clear_cmdline */
  340.     }
  341.  
  342.     /*
  343.      * Only start redrawing if there is really something to do.
  344.      */
  345.     if (type == INVERTED)
  346.     update_curswant();
  347.     if (!((type == VALID && curwin->w_topline == curwin->w_lsize_lnum[0])
  348.         || (type == INVERTED
  349.         && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
  350.         && (curwin->w_valid & VALID_VIRTCOL)
  351.         && curwin->w_old_curswant == curwin->w_curswant)))
  352.     {
  353.     /*
  354.      * go from top to bottom through the windows, redrawing the ones that
  355.      * need it
  356.      */
  357.     curwin->w_redr_type = type;
  358.     cursor_off();
  359. #ifdef EXTRA_SEARCH
  360.     start_search_hl();
  361. #endif
  362.     for (wp = firstwin; wp; wp = wp->w_next)
  363.     {
  364.         if (wp->w_redr_type)
  365.         win_update(wp);
  366.         if (wp->w_redr_status)
  367.         win_redr_status(wp);
  368.     }
  369. #ifdef EXTRA_SEARCH
  370.     end_search_hl();
  371. #endif
  372.     }
  373.     if (redraw_cmdline)
  374.     showmode();
  375.  
  376.     display_hint = HINT_NONE;
  377.  
  378.     /* May put up an introductory message when not editing a file */
  379.     if (!did_intro && bufempty()
  380.         && curbuf->b_fname == NULL
  381.         && firstwin->w_next == NULL
  382.         && vim_strchr(p_shm, SHM_INTRO) == NULL)
  383.     intro_message();
  384.     did_intro = TRUE;
  385. }
  386.  
  387. #ifdef USE_GUI
  388. /*
  389.  * Update a single window, its status line and maybe the command line msg.
  390.  * Used for the GUI scrollbar.
  391.  */
  392.     void
  393. updateWindow(wp)
  394.     WIN        *wp;
  395. {
  396.     cursor_off();
  397. #ifdef EXTRA_SEARCH
  398.     start_search_hl();
  399. #endif
  400.     win_update(wp);
  401.     if (wp->w_redr_status)
  402.     win_redr_status(wp);
  403.     if (redraw_cmdline)
  404.     showmode();
  405. #ifdef EXTRA_SEARCH
  406.     end_search_hl();
  407. #endif
  408. }
  409. #endif
  410.  
  411. /*
  412.  * Update all windows for the current buffer, except curwin.
  413.  * Used after modifying text, to update the other windows on the same buffer.
  414.  */
  415.     void
  416. update_other_win()
  417. {
  418.     WIN        *wp;
  419.     int        first = TRUE;
  420.  
  421.     for (wp = firstwin; wp; wp = wp->w_next)
  422.     if (wp != curwin && wp->w_buffer == curbuf)
  423.     {
  424.         if (first)
  425.         {
  426.         cursor_off();
  427. #ifdef EXTRA_SEARCH
  428.         start_search_hl();
  429. #endif
  430.         first = FALSE;
  431.         }
  432.         wp->w_redr_type = NOT_VALID;
  433.         /*
  434.          * don't do the actual redraw if wait_return() has just been
  435.          * called and the user typed a ":"
  436.          */
  437.         if (!skip_redraw)
  438.         win_update(wp);
  439.     }
  440.  
  441. #ifdef EXTRA_SEARCH
  442.     end_search_hl();
  443. #endif
  444. }
  445.  
  446. /*
  447.  * Update a single window.
  448.  *
  449.  * This may cause the windows below it also to be redrawn.
  450.  */
  451.     static void
  452. win_update(wp)
  453.     WIN        *wp;
  454. {
  455.     int            type = wp->w_redr_type;
  456.     int            row;
  457.     int            endrow;
  458.     linenr_t        lnum;
  459.     linenr_t        lastline;        /* only valid if endrow != Rows -1 */
  460.     int            done;        /* if TRUE, we hit the end of the file */
  461.     int            didline;        /* if TRUE, we finished the last line */
  462.     int            srow = 0;        /* starting row of the current line */
  463.     int            idx;
  464.     int            i;
  465.     long        j;
  466.     static int        recursive = FALSE;    /* being called recursively */
  467.     int            old_botline = wp->w_botline;
  468.     int            must_start_top = FALSE; /* update must start at top row */
  469.     int            must_end_bot = FALSE;   /* update must end at bottom row */
  470.  
  471.     if (type == NOT_VALID)
  472.     {
  473.     wp->w_redr_status = TRUE;
  474.     wp->w_lsize_valid = 0;
  475.     }
  476.  
  477.     idx = 0;
  478.     row = 0;
  479.     lnum = wp->w_topline;
  480.     validate_virtcol_win(wp);
  481.  
  482.     /* The number of rows shown is w_height. */
  483.     /* The default last row is the status/command line. */
  484.     endrow = wp->w_height;
  485.  
  486.     /*
  487.      * If there are no changes on the screen, handle two special cases:
  488.      * 1: we are off the top of the screen by a few lines: scroll down
  489.      * 2: wp->w_topline is below wp->w_lsize_lnum[0]: may scroll up
  490.      */
  491.     if (type == VALID || type == VALID_TO_CURSCHAR ||
  492.         type == VALID_BEF_CURSCHAR || type == INVERTED)
  493.     {
  494.     if (wp->w_topline < wp->w_lsize_lnum[0])    /* may scroll down */
  495.     {
  496.         j = wp->w_lsize_lnum[0] - wp->w_topline;
  497.         if (j < wp->w_height - 2            /* not too far off */
  498.             && (type != VALID_TO_CURSCHAR
  499.                    || wp->w_lsize_lnum[0] < curwin->w_cursor.lnum)
  500.             && (type != VALID_BEF_CURSCHAR
  501.               || wp->w_lsize_lnum[0] < curwin->w_cursor.lnum - 1))
  502.         {
  503.         lastline = wp->w_lsize_lnum[0] - 1;
  504.         i = plines_m_win(wp, wp->w_topline, lastline);
  505.         if (i < wp->w_height - 2)    /* less than a screen off */
  506.         {
  507.             /*
  508.              * Try to insert the correct number of lines.
  509.              * If not the last window, delete the lines at the bottom.
  510.              * win_ins_lines may fail.
  511.              */
  512.             if (i > 0)
  513.             check_for_delay(FALSE);
  514.             if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK
  515.                              && wp->w_lsize_valid)
  516.             {
  517.             must_start_top = TRUE;
  518.             endrow = i;
  519.  
  520.             if ((wp->w_lsize_valid += j) > wp->w_height)
  521.                 wp->w_lsize_valid = wp->w_height;
  522.             for (idx = wp->w_lsize_valid; idx - j >= 0; idx--)
  523.             {
  524.                 wp->w_lsize_lnum[idx] = wp->w_lsize_lnum[idx - j];
  525.                 wp->w_lsize[idx] = wp->w_lsize[idx - j];
  526.             }
  527.             idx = 0;
  528.             }
  529.         }
  530.         else if (lastwin == firstwin)
  531.         {
  532.             screenclear();  /* far off: clearing the screen is faster */
  533.             must_start_top = TRUE;
  534.             must_end_bot = TRUE;
  535.         }
  536.         }
  537.         else if (lastwin == firstwin)
  538.         {
  539.         screenclear();        /* far off: clearing the screen is faster */
  540.         must_start_top = TRUE;
  541.         must_end_bot = TRUE;
  542.         }
  543.     }
  544.     else                /* may scroll up */
  545.     {
  546.         j = -1;
  547.             /* try to find wp->w_topline in wp->w_lsize_lnum[] */
  548.         for (i = 0; i < wp->w_lsize_valid; i++)
  549.         {
  550.         if (wp->w_lsize_lnum[i] == wp->w_topline)
  551.         {
  552.             j = i;
  553.             break;
  554.         }
  555.         row += wp->w_lsize[i];
  556.         }
  557.         if (j == -1)    /* wp->w_topline is not in wp->w_lsize_lnum */
  558.         {
  559.         row = 0;    /* start at the first row */
  560.         if (lastwin == firstwin)
  561.         {
  562.             screenclear();  /* far off: clearing the screen is faster */
  563.             must_start_top = TRUE;
  564.             must_end_bot = TRUE;
  565.         }
  566.         }
  567.         else
  568.         {
  569.         /*
  570.          * Try to delete the correct number of lines.
  571.          * wp->w_topline is at wp->w_lsize_lnum[i].
  572.          */
  573.         if (row)
  574.         {
  575.             check_for_delay(FALSE);
  576.             if (win_del_lines(wp, 0, row, FALSE, wp == firstwin) == OK)
  577.             must_end_bot = TRUE;
  578.         }
  579.         if ((row == 0 || must_end_bot) && wp->w_lsize_valid)
  580.         {
  581.             /*
  582.              * Skip the lines (below the deleted lines) that are still
  583.              * valid and don't need redrawing.    Copy their info
  584.              * upwards, to compensate for the deleted lines.  Leave
  585.              * row and lnum on the first line that needs redrawing.
  586.              */
  587.             srow = row;
  588.             row = 0;
  589.             for (;;)
  590.             {
  591.             if ((type == VALID_TO_CURSCHAR &&
  592.                          lnum == wp->w_cursor.lnum) ||
  593.                 (type == VALID_BEF_CURSCHAR &&
  594.                            lnum == wp->w_cursor.lnum - 1))
  595.             {
  596.                 wp->w_lsize_valid = idx;
  597.                 break;
  598.             }
  599.             wp->w_lsize[idx] = wp->w_lsize[j];
  600.             wp->w_lsize_lnum[idx] = lnum;
  601.             if (row + srow + (int)wp->w_lsize[j] > wp->w_height)
  602.             {
  603.                 wp->w_lsize_valid = idx + 1;
  604.                 break;
  605.             }
  606.             ++lnum;
  607.  
  608.             row += wp->w_lsize[idx++];
  609.             if ((int)++j >= wp->w_lsize_valid)
  610.             {
  611.                 wp->w_lsize_valid = idx;
  612.                 break;
  613.             }
  614.             }
  615.         }
  616.         else
  617.             row = 0;        /* update all lines */
  618.         }
  619.     }
  620.     if (endrow == wp->w_height && idx == 0)        /* no scrolling */
  621.         wp->w_lsize_valid = 0;
  622.     }
  623.  
  624.     done = didline = FALSE;
  625.  
  626.     if (VIsual_active)        /* check if we are updating the inverted part */
  627.     {
  628.     linenr_t    from, to;
  629.  
  630.     /*
  631.      * Find the line numbers that need to be updated: The lines between
  632.      * the old cursor position and the current cursor position.  Also
  633.      * check if the Visual position changed.
  634.      */
  635.     if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
  636.     {
  637.         from = curwin->w_cursor.lnum;
  638.         to = wp->w_old_cursor_lnum;
  639.     }
  640.     else
  641.     {
  642.         from = wp->w_old_cursor_lnum;
  643.         to = curwin->w_cursor.lnum;
  644.     }
  645.  
  646.     if (VIsual.lnum != wp->w_old_visual_lnum)
  647.     {
  648.         if (wp->w_old_visual_lnum < from)
  649.         from = wp->w_old_visual_lnum;
  650.         if (wp->w_old_visual_lnum > to)
  651.         to = wp->w_old_visual_lnum;
  652.         if (VIsual.lnum < from)
  653.         from = VIsual.lnum;
  654.         if (VIsual.lnum > to)
  655.         to = VIsual.lnum;
  656.     }
  657.  
  658.     /*
  659.      * If in block mode and changed column or curwin->w_curswant: update
  660.      * all lines.
  661.      * First compute the actual start and end column.
  662.      */
  663.     if (VIsual_mode == Ctrl('V'))
  664.     {
  665.         colnr_t    from1, from2, to1, to2;
  666.  
  667.         getvcol(wp, &VIsual, &from1, NULL, &to1);
  668.         getvcol(wp, &curwin->w_cursor, &from2, NULL, &to2);
  669.         if (from2 < from1)
  670.         from1 = from2;
  671.         if (to2 > to1)
  672.         to1 = to2;
  673.         ++to1;
  674.         if (curwin->w_curswant == MAXCOL)
  675.         to1 = MAXCOL;
  676.  
  677.         if (from1 != wp->w_old_cursor_fcol || to1 != wp->w_old_cursor_lcol)
  678.         {
  679.         if (from > VIsual.lnum)
  680.             from = VIsual.lnum;
  681.         if (to < VIsual.lnum)
  682.             to = VIsual.lnum;
  683.         }
  684.         wp->w_old_cursor_fcol = from1;
  685.         wp->w_old_cursor_lcol = to1;
  686.     }
  687.  
  688.     /*
  689.      * There is no need to update lines above the top of the window.
  690.      * If "must_start_top" is set, always start at w_topline.
  691.      */
  692.     if (from < wp->w_topline || must_start_top)
  693.         from = wp->w_topline;
  694.  
  695.     /*
  696.      * If we know the value of w_botline, use it to restrict the update to
  697.      * the lines that are visible in the window.
  698.      */
  699.     if (wp->w_valid & VALID_BOTLINE)
  700.     {
  701.         if (from >= wp->w_botline)
  702.         from = wp->w_botline - 1;
  703.         if (to >= wp->w_botline)
  704.         to = wp->w_botline - 1;
  705.     }
  706.  
  707.     /*
  708.      * Find the minimal part to be updated.
  709.      *
  710.      * If "lnum" is past "from" already, start at w_topline (can
  711.      * happen when scrolling).
  712.      */
  713.     if (lnum > from)
  714.     {
  715.         lnum = wp->w_topline;
  716.         idx = 0;
  717.         row = 0;
  718.     }
  719.     while (lnum < from && idx < wp->w_lsize_valid)        /* find start */
  720.     {
  721.         row += wp->w_lsize[idx++];
  722.         ++lnum;
  723.     }
  724.     if (!must_end_bot && !must_start_top)
  725.     {
  726.         srow = row;
  727.         for (j = idx; j < wp->w_lsize_valid; ++j)        /* find end */
  728.         {
  729.         if (wp->w_lsize_lnum[j] == to + 1)
  730.         {
  731.             endrow = srow;
  732.             break;
  733.         }
  734.         srow += wp->w_lsize[j];
  735.         }
  736.     }
  737.     else
  738.     {
  739.         /* Redraw until the end, otherwise we could miss something when
  740.          * doing CTRL-U. */
  741.         endrow = wp->w_height;
  742.     }
  743.  
  744.     wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
  745.     wp->w_old_visual_lnum = VIsual.lnum;
  746.     wp->w_old_curswant = curwin->w_curswant;
  747.     }
  748.     else
  749.     {
  750.     wp->w_old_cursor_lnum = 0;
  751.     wp->w_old_visual_lnum = 0;
  752.     }
  753.  
  754.     /*
  755.      * Update the screen rows from "row" to "endrow".
  756.      * Start at line "lnum" which is at wp->w_lsize_lnum[idx].
  757.      */
  758.     for (;;)
  759.     {
  760.     if (row == endrow)
  761.     {
  762.         didline = TRUE;
  763.         break;
  764.     }
  765.  
  766.     if (lnum > wp->w_buffer->b_ml.ml_line_count)
  767.     {
  768.         done = TRUE;    /* hit the end of the file */
  769.         break;
  770.     }
  771.     srow = row;
  772.     row = win_line(wp, lnum, srow, endrow);
  773.     if (row > endrow)    /* past end of screen */
  774.     {
  775.         /* we may need the size of that too long line later on */
  776.         wp->w_lsize[idx] = plines_win(wp, lnum);
  777.         wp->w_lsize_lnum[idx++] = lnum;
  778.         break;
  779.     }
  780.  
  781.     wp->w_lsize[idx] = row - srow;
  782.     wp->w_lsize_lnum[idx++] = lnum;
  783.     if (++lnum > wp->w_buffer->b_ml.ml_line_count)
  784.     {
  785.         done = TRUE;
  786.         break;
  787.     }
  788.     }
  789.     if (idx > wp->w_lsize_valid)
  790.     wp->w_lsize_valid = idx;
  791.  
  792.     /* Do we have to do off the top of the screen processing ? */
  793.     if (endrow != wp->w_height)
  794.     {
  795.     row = 0;
  796.     for (idx = 0; idx < wp->w_lsize_valid && row < wp->w_height; idx++)
  797.         row += wp->w_lsize[idx];
  798.  
  799.     if (row < wp->w_height)
  800.     {
  801.         done = TRUE;
  802.     }
  803.     else if (row > wp->w_height)    /* Need to blank out the last line */
  804.     {
  805.         lnum = wp->w_lsize_lnum[idx - 1];
  806.         srow = row - wp->w_lsize[idx - 1];
  807.         didline = FALSE;
  808.     }
  809.     else
  810.     {
  811.         lnum = wp->w_lsize_lnum[idx - 1] + 1;
  812.         didline = TRUE;
  813.     }
  814.     }
  815.  
  816.     wp->w_empty_rows = 0;
  817.     /*
  818.      * If we didn't hit the end of the file, and we didn't finish the last
  819.      * line we were working on, then the line didn't fit.
  820.      */
  821.     if (!done && !didline)
  822.     {
  823.     if (lnum == wp->w_topline)
  824.     {
  825.         /*
  826.          * Single line that does not fit!
  827.          * Fill last line with '@' characters.
  828.          */
  829.         screen_fill(wp->w_winpos + wp->w_height - 1,
  830.             wp->w_winpos + wp->w_height, 0, (int)Columns, '@', '@',
  831.             highlight_attr[HLF_AT]);
  832.         wp->w_botline = lnum + 1;
  833.     }
  834.     else
  835.     {
  836.         /*
  837.          * Clear the rest of the screen and mark the unused lines.
  838.          */
  839. #ifdef RIGHTLEFT
  840.         if (wp->w_p_rl)
  841.         {
  842.         screen_fill(wp->w_winpos + srow,
  843.             wp->w_winpos + wp->w_height, 0, (int)Columns - 1,
  844.             ' ', ' ', highlight_attr[HLF_AT]);
  845.         screen_fill(wp->w_winpos + srow,
  846.             wp->w_winpos + wp->w_height, (int)Columns - 1,
  847.             (int)Columns, '@', ' ', highlight_attr[HLF_AT]);
  848.         }
  849.         else
  850. #endif
  851.         screen_fill(wp->w_winpos + srow,
  852.             wp->w_winpos + wp->w_height, 0, (int)Columns, '@', ' ',
  853.             highlight_attr[HLF_AT]);
  854.         wp->w_botline = lnum;
  855.         wp->w_empty_rows = wp->w_height - srow;
  856.     }
  857.     }
  858.     else
  859.     {
  860.     /* make sure the rest of the screen is blank */
  861.     /* put '~'s on rows that aren't part of the file. */
  862. #ifdef RIGHTLEFT
  863.     if (wp->w_p_rl)
  864.     {
  865.         screen_fill(wp->w_winpos + row,
  866.             wp->w_winpos + wp->w_height, 0, (int)Columns - 1,
  867.             ' ', ' ', highlight_attr[HLF_AT]);
  868.         screen_fill(wp->w_winpos + row,
  869.             wp->w_winpos + wp->w_height, (int)Columns - 1,
  870.             (int)Columns, '~', ' ', highlight_attr[HLF_AT]);
  871.     }
  872.     else
  873. #endif
  874.         screen_fill(wp->w_winpos + row,
  875.             wp->w_winpos + wp->w_height, 0, (int)Columns, '~', ' ',
  876.             highlight_attr[HLF_AT]);
  877.     wp->w_empty_rows = wp->w_height - row;
  878.  
  879.     if (done)        /* we hit the end of the file */
  880.         wp->w_botline = wp->w_buffer->b_ml.ml_line_count + 1;
  881.     else
  882.         wp->w_botline = lnum;
  883.     }
  884.  
  885.     /*
  886.      * There is a trick with w_botline.  If we invalidate it on each change
  887.      * that might modify it, this will cause a lot of expensive calls to
  888.      * plines() in update_topline() each time.    Therefore the value of
  889.      * w_botline is often approximated, and this value is used to compute the
  890.      * value of w_topline.  If the value of w_botline was wrong, check that
  891.      * the value of w_topline is correct (cursor is on the visible part of the
  892.      * text).  If it's not, we need to redraw again.  Mostly this just means
  893.      * scrolling up a few lines, so it doesn't look too bad.  Only do this for
  894.      * the current window (where changes are relevant).
  895.      */
  896.     wp->w_valid |= VALID_BOTLINE;
  897.     wp->w_redr_type = 0;
  898.     if (wp == curwin && wp->w_botline != old_botline && !recursive)
  899.     {
  900.     recursive = TRUE;
  901.     update_topline();    /* may invalidate w_botline again */
  902.     if (must_redraw)
  903.     {
  904.         win_update(wp);
  905.         must_redraw = 0;
  906.     }
  907.     recursive = FALSE;
  908.     }
  909. }
  910.  
  911. /*
  912.  * Display line "lnum" of window 'wp' on the screen.
  913.  * Start at row "startrow", stop when "endrow" is reached.
  914.  * wp->w_virtcol needs to be valid.
  915.  *
  916.  * Return the number of last row the line occupies.
  917.  */
  918.  
  919.     static int
  920. win_line(wp, lnum, startrow, endrow)
  921.     WIN            *wp;
  922.     linenr_t        lnum;
  923.     int            startrow;
  924.     int            endrow;
  925. {
  926.     char_u        *screenp;
  927.     int            c = 0;        /* init for GCC */
  928.     int            col;        /* visual column on screen */
  929.     long        vcol;        /* visual column for tabs */
  930. #ifdef SYNTAX_HL
  931.     int            rcol;        /* real column in the line */
  932. #endif
  933.     int            row;        /* row in the window, excl w_winpos */
  934.     int            screen_row;        /* row on the screen, incl w_winpos */
  935.     char_u        *ptr;
  936. #ifdef SYNTAX_HL
  937.     char_u        *line;
  938. #endif
  939.     char_u        extra[16];        /* "%ld" must fit in here */
  940.     char_u        *p_extra;
  941.     char_u        *showbreak = NULL;
  942.     int            n_extra;
  943.     int            n_spaces = 0;
  944.  
  945.     int            fromcol, tocol;    /* start/end of inverting */
  946.     int            noinvcur = FALSE;    /* don't invert the cursor */
  947.     FPOS        *top, *bot;
  948.     int            area_highlighting;    /* Visual or incsearch highlighting in
  949.                        this line */
  950.     int            attr;        /* attributes for area highlighting */
  951.     int            area_attr = 0;    /* attributes desired by highlighting */
  952.     int            search_attr = 0;    /* attributes sesired by 'searchhl' */
  953. #ifdef SYNTAX_HL
  954.     int            syntax_attr = 0;    /* attributes desired by syntax */
  955.     int            has_syntax = FALSE;    /* this buffer has syntax highl. */
  956. #endif
  957.     int            has_syn_or_lbr;    /* has syntax or linebreak */
  958.     int            char_attr;        /* attributes for next character */
  959.     int            saved_attr = 0;    /* char_attr saved for showbreak */
  960. #ifdef EXTRA_SEARCH
  961.     char_u        *matchp;
  962.     char_u        *search_hl_start = NULL;
  963.     char_u        *search_hl_end = NULL;
  964. #endif
  965.  
  966.     if (startrow > endrow)        /* past the end already! */
  967.     return startrow;
  968.  
  969.     row = startrow;
  970.     screen_row = row + wp->w_winpos;
  971.     attr = highlight_attr[HLF_V];
  972.  
  973.     /*
  974.      * To speed up the loop below, set has_syn_or_lbr when there is linebreak
  975.      * and/or syntax processing to be done.
  976.      */
  977.     has_syn_or_lbr = wp->w_p_lbr;
  978. #ifdef SYNTAX_HL
  979.     if (syntax_present(wp->w_buffer))
  980.     {
  981.     syntax_start(wp, lnum);
  982.     has_syntax = TRUE;
  983.     has_syn_or_lbr = TRUE;
  984.     }
  985. #endif
  986.     col = 0;
  987.     vcol = 0;
  988.     fromcol = -10;
  989.     tocol = MAXCOL;
  990.     area_highlighting = FALSE;
  991.     char_attr = 0;
  992.  
  993.     /*
  994.      * handle visual active in this window
  995.      */
  996.     if (VIsual_active && wp->w_buffer == curwin->w_buffer)
  997.     {
  998.                     /* Visual is after curwin->w_cursor */
  999.     if (ltoreq(curwin->w_cursor, VIsual))
  1000.     {
  1001.         top = &curwin->w_cursor;
  1002.         bot = &VIsual;
  1003.     }
  1004.     else                /* Visual is before curwin->w_cursor */
  1005.     {
  1006.         top = &VIsual;
  1007.         bot = &curwin->w_cursor;
  1008.     }
  1009.     if (VIsual_mode == Ctrl('V'))    /* block mode */
  1010.     {
  1011.         if (lnum >= top->lnum && lnum <= bot->lnum)
  1012.         {
  1013.         fromcol = wp->w_old_cursor_fcol;
  1014.         tocol = wp->w_old_cursor_lcol;
  1015.         }
  1016.     }
  1017.     else                /* non-block mode */
  1018.     {
  1019.         if (lnum > top->lnum && lnum <= bot->lnum)
  1020.         fromcol = 0;
  1021.         else if (lnum == top->lnum)
  1022.         getvcol(wp, top, (colnr_t *)&fromcol, NULL, NULL);
  1023.         if (lnum == bot->lnum)
  1024.         {
  1025.         getvcol(wp, bot, NULL, NULL, (colnr_t *)&tocol);
  1026.         ++tocol;
  1027.         }
  1028.  
  1029.         if (VIsual_mode == 'V')    /* linewise */
  1030.         {
  1031.         if (fromcol > 0)
  1032.             fromcol = 0;
  1033.         tocol = MAXCOL;
  1034.         }
  1035.     }
  1036.         /* if the cursor can't be switched off, don't invert the
  1037.          * character where the cursor is */
  1038. #ifndef MSDOS
  1039.     if (!highlight_match && *T_VI == NUL &&
  1040.                 lnum == curwin->w_cursor.lnum && wp == curwin)
  1041.         noinvcur = TRUE;
  1042. #endif
  1043.  
  1044.     if (tocol <= (int)wp->w_leftcol)    /* inverting is left of screen */
  1045.         fromcol = 0;
  1046.                     /* start of invert is left of screen */
  1047.     else if (fromcol >= 0 && fromcol < (int)wp->w_leftcol)
  1048.         fromcol = wp->w_leftcol;
  1049.  
  1050.     /* if inverting in this line, can't optimize cursor positioning */
  1051.     if (fromcol >= 0)
  1052.         area_highlighting = TRUE;
  1053.     }
  1054.  
  1055.     /*
  1056.      * handle incremental search position highlighting
  1057.      */
  1058.     else if (highlight_match && wp == curwin && search_match_len)
  1059.     {
  1060.     if (lnum == curwin->w_cursor.lnum)
  1061.     {
  1062.         getvcol(curwin, &(curwin->w_cursor),
  1063.                         (colnr_t *)&fromcol, NULL, NULL);
  1064.         curwin->w_cursor.col += search_match_len;
  1065.         getvcol(curwin, &(curwin->w_cursor),
  1066.                         (colnr_t *)&tocol, NULL, NULL);
  1067.         curwin->w_cursor.col -= search_match_len;
  1068.         area_highlighting = TRUE;
  1069.         attr = highlight_attr[HLF_I];
  1070.         if (fromcol == tocol)    /* do at least one character */
  1071.         tocol = fromcol + 1;    /* happens when past end of line */
  1072.     }
  1073.     }
  1074.  
  1075.     ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
  1076. #ifdef EXTRA_SEARCH
  1077.     matchp = ptr;
  1078. #endif
  1079. #ifdef SYNTAX_HL
  1080.     line = ptr;
  1081.     rcol = 0;
  1082. #endif
  1083.  
  1084.     if (!wp->w_p_wrap)        /* advance to first character to be displayed */
  1085.     {
  1086.     while ((colnr_t)vcol < wp->w_leftcol && *ptr)
  1087.     {
  1088.         vcol += win_chartabsize(wp, *ptr++, (colnr_t)vcol);
  1089. #ifdef SYNTAX_HL
  1090.         ++rcol;
  1091. #endif
  1092.     }
  1093.     if ((colnr_t)vcol > wp->w_leftcol)
  1094.     {
  1095.         n_spaces = vcol - wp->w_leftcol;    /* begin with some spaces */
  1096.         vcol = wp->w_leftcol;
  1097.     }
  1098.     }
  1099.  
  1100. #ifdef EXTRA_SEARCH
  1101.     /*
  1102.      * Handle highlighting the last used search pattern.
  1103.      */
  1104.     if (search_hl_prog != NULL)
  1105.     {
  1106.     reg_ic = search_hl_ic;
  1107.     for (;;)
  1108.     {
  1109.         if (vim_regexec(search_hl_prog, matchp, TRUE))
  1110.         {
  1111.         search_hl_start = search_hl_prog->startp[0];
  1112.         search_hl_end = search_hl_prog->endp[0];
  1113.         if (search_hl_end <= ptr)    /* match before leftcol */
  1114.         {
  1115.             if (matchp == search_hl_end) /* empty match */
  1116.             ++matchp;
  1117.             else
  1118.             matchp = search_hl_end;
  1119.             continue;
  1120.         }
  1121.         if (search_hl_start < ptr)  /* match at leftcol */
  1122.             search_attr = search_hl_attr;
  1123.         }
  1124.         else
  1125.         {
  1126.         search_hl_start = NULL;
  1127.         search_hl_end = NULL;
  1128.         }
  1129.         break;
  1130.     }
  1131.     if (search_hl_start != NULL)
  1132.         area_highlighting = TRUE;
  1133.     }
  1134. #endif
  1135.  
  1136.     screenp = current_LinePointer;
  1137. #ifdef RIGHTLEFT
  1138.     if (wp->w_p_rl)
  1139.     {
  1140.     col = Columns - 1;            /* col follows screenp here */
  1141.     screenp += Columns - 1;
  1142.     }
  1143. #endif
  1144.     if (wp->w_p_nu)
  1145.     {
  1146. #ifdef RIGHTLEFT
  1147.     if (wp->w_p_rl)                /* reverse line numbers */
  1148.     {
  1149.         char_u *c1, *c2, t;
  1150.  
  1151.         sprintf((char *)extra, " %-7ld", (long)lnum);
  1152.         for (c1 = extra, c2 = extra + STRLEN(extra) - 1; c1 < c2;
  1153.                                    c1++, c2--)
  1154.         {
  1155.         t = *c1;
  1156.         *c1 = *c2;
  1157.         *c2 = t;
  1158.         }
  1159.     }
  1160.     else
  1161. #endif
  1162.         sprintf((char *)extra, "%7ld ", (long)lnum);
  1163.     p_extra = extra;
  1164.     n_extra = 8;
  1165.     vcol -= 8;    /* so vcol is 0 when line number has been printed */
  1166.     }
  1167.     else
  1168.     {
  1169.     p_extra = NULL;
  1170.     n_extra = 0;
  1171.     }
  1172.  
  1173.     for (;;)
  1174.     {
  1175.     if (area_highlighting)    /* Visual or match highlighting in this line */
  1176.     {
  1177.         if (((vcol == fromcol && !(noinvcur &&
  1178.                        (colnr_t)vcol == wp->w_virtcol)) ||
  1179.             (noinvcur && (colnr_t)vcol == wp->w_virtcol + 1 &&
  1180.                 vcol >= fromcol)) && vcol < tocol)
  1181.         area_attr = attr;            /* start highlighting */
  1182.         else if (area_attr && (vcol == tocol ||
  1183.                 (noinvcur && (colnr_t)vcol == wp->w_virtcol)))
  1184.         area_attr = 0;                /* stop highlighting */
  1185.  
  1186. #ifdef EXTRA_SEARCH
  1187.         /*
  1188.          * Check for start/end of search pattern match.
  1189.          * After end, check for start/end of next match.
  1190.          * When another match, have to check for start again.
  1191.          * Watch out for matching an empty string!
  1192.          */
  1193.         if (!n_extra && !n_spaces)
  1194.         {
  1195.         for (;;)
  1196.         {
  1197.             if (ptr == search_hl_start)
  1198.             search_attr = search_hl_attr;
  1199.             if (ptr == search_hl_end)
  1200.             {
  1201.             search_attr = 0;
  1202.             reg_ic = search_hl_ic;
  1203.             if (vim_regexec(search_hl_prog, ptr, FALSE))
  1204.             {
  1205.                 search_hl_start = search_hl_prog->startp[0];
  1206.                 search_hl_end = search_hl_prog->endp[0];
  1207.                 if (search_hl_start != search_hl_end)
  1208.                 continue;
  1209.                 ++search_hl_end; /* try again after empty match */
  1210.             }
  1211.             }
  1212.             break;
  1213.         }
  1214.         }
  1215. #endif
  1216.  
  1217.         if (area_attr)
  1218.         char_attr = area_attr;
  1219. #ifdef SYNTAX_HL
  1220.         else if (!search_attr && has_syntax)
  1221.         char_attr = syntax_attr;
  1222. #endif
  1223.         else
  1224.         char_attr = search_attr;
  1225.     }
  1226.  
  1227.     /* Get the next character to put on the screen. */
  1228.  
  1229.     /*
  1230.      * If 'showbreak' is set it contains the characters to put at the
  1231.      * start of each broken line.
  1232.      */
  1233.     if (
  1234. #ifdef RIGHTLEFT
  1235.         (wp->w_p_rl ? col == -1 : col == Columns)
  1236. #else
  1237.         col == Columns
  1238. #endif
  1239.         && (*ptr != NUL
  1240.             || (wp->w_p_list && n_extra == 0)
  1241.             || (n_extra && *p_extra)
  1242.             || n_spaces)
  1243.         && vcol != 0 && *p_sbr != 0)
  1244.     {
  1245.         showbreak = p_sbr;
  1246.         saved_attr = char_attr;        /* save current attributes */
  1247.     }
  1248.     if (showbreak != NULL)
  1249.     {
  1250.         if (*showbreak == NUL)
  1251.         {
  1252.         showbreak = NULL;
  1253.         char_attr = saved_attr;        /* restore attributes */
  1254.         }
  1255.         else
  1256.         {
  1257.         c = *showbreak++;
  1258.         char_attr = highlight_attr[HLF_AT];
  1259.         }
  1260.     }
  1261.  
  1262.     if (showbreak == NULL)
  1263.     {
  1264.         /*
  1265.          * The 'extra' array contains the extra stuff that is inserted to
  1266.          * represent special characters (non-printable stuff).
  1267.          */
  1268.         if (n_extra)
  1269.         {
  1270.         c = *p_extra++;
  1271.         n_extra--;
  1272.         }
  1273.         else if (n_spaces)
  1274.         {
  1275.         c = ' ';
  1276.         n_spaces--;
  1277.         }
  1278.         else
  1279.         {
  1280.         c = *ptr++;
  1281.  
  1282.         if (has_syn_or_lbr)
  1283.         {
  1284. #ifdef SYNTAX_HL
  1285.             if (has_syntax)
  1286.             {
  1287.             syntax_attr = get_syntax_attr(rcol++, line);
  1288.             if (!area_attr && !search_attr)
  1289.                 char_attr = syntax_attr;
  1290.             }
  1291. #endif
  1292.             /*
  1293.              * Found last space before word: check for line break
  1294.              */
  1295.             if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr)
  1296.                               && !wp->w_p_list)
  1297.             {
  1298.             n_spaces = win_lbr_chartabsize(wp, ptr - 1,
  1299.                 (colnr_t)vcol, NULL) - 1;
  1300.             if (vim_iswhite(c))
  1301.                 c = ' ';
  1302.             }
  1303.         }
  1304.  
  1305.         /*
  1306.          * Handling of non-printable characters.
  1307.          */
  1308.         if (!safe_vim_isprintc(c))
  1309.         {
  1310.             /*
  1311.              * when getting a character from the file, we may have to
  1312.              * turn it into something else on the way to putting it
  1313.              * into 'NextScreen'.
  1314.              */
  1315.             if (c == TAB && !wp->w_p_list)
  1316.             {
  1317.             /* tab amount depends on current column */
  1318.             n_spaces = (int)wp->w_buffer->b_p_ts -
  1319.                      vcol % (int)wp->w_buffer->b_p_ts - 1;
  1320.             c = ' ';
  1321.             }
  1322.             else if (c == NUL && wp->w_p_list)
  1323.             {
  1324.             p_extra = (char_u *)"";
  1325.             n_extra = 1;
  1326.             c = '$';
  1327.             --ptr;        /* put it back at the NUL */
  1328.             char_attr = highlight_attr[HLF_AT];
  1329.             }
  1330.             else if (c != NUL)
  1331.             {
  1332.             p_extra = transchar(c);
  1333.             n_extra = charsize(c) - 1;
  1334.             c = *p_extra++;
  1335.             }
  1336.         }
  1337.         }
  1338.     }
  1339.  
  1340.     /*
  1341.      * At end of the text line.
  1342.      */
  1343.     if (c == NUL)
  1344.     {
  1345.         if (area_attr)
  1346.         {
  1347.         /* invert at least one char, used for Visual and empty line or
  1348.          * highlight match at end of line. If it's beyond the last
  1349.          * char on the screen, just overwrite that one (tricky!) */
  1350.         if (vcol == fromcol)
  1351.         {
  1352. #ifdef RIGHTLEFT
  1353.             if (wp->w_p_rl)
  1354.             {
  1355.             if (col < 0)
  1356.             {
  1357.                 ++screenp;
  1358.                 ++col;
  1359.             }
  1360.             }
  1361.             else
  1362. #endif
  1363.             {
  1364.             if (col >= Columns)
  1365.             {
  1366.                 --screenp;
  1367.                 --col;
  1368.             }
  1369.             }
  1370.             *screenp = ' ';
  1371.             *(screenp + Columns) = char_attr;
  1372. #ifdef RIGHTLEFT
  1373.             if (wp->w_p_rl)
  1374.             --col;
  1375.             else
  1376. #endif
  1377.             ++col;
  1378.         }
  1379.         }
  1380.  
  1381.         SCREEN_LINE(screen_row, col, TRUE, wp->w_p_rl);
  1382.         row++;
  1383.  
  1384.         /*
  1385.          * Update w_cline_height if we can (saves a call to plines()
  1386.          * later).
  1387.          */
  1388.         if (wp == curwin && lnum == curwin->w_cursor.lnum)
  1389.         {
  1390.         curwin->w_cline_row = startrow;
  1391.         curwin->w_cline_height = row - startrow;
  1392.         curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
  1393.         }
  1394.  
  1395.         break;
  1396.     }
  1397.  
  1398.     /*
  1399.      * At end of screen line.
  1400.      */
  1401.     if (
  1402. #ifdef RIGHTLEFT
  1403.         wp->w_p_rl ? (col < 0) :
  1404. #endif
  1405.                     (col >= Columns)
  1406.                             )
  1407.     {
  1408.         SCREEN_LINE(screen_row, col, TRUE, wp->w_p_rl);
  1409.         col = 0;
  1410.         ++row;
  1411.         ++screen_row;
  1412.         if (!wp->w_p_wrap)
  1413.         break;
  1414.         if (row == endrow)        /* line got too long for screen */
  1415.         {
  1416.         ++row;
  1417.         break;
  1418.         }
  1419.  
  1420.         /*
  1421.          * Special trick to make copy/paste of wrapped lines work with
  1422.          * xterm/screen: write an extra character beyond the end of the
  1423.          * line. This will work with all terminal types (regardless of the
  1424.          * xn,am settings).
  1425.          * Only do this on a fast tty.
  1426.          * Only do this if the cursor is on the current line (something
  1427.          * has been written in it).
  1428.          * Don't do this for the GUI.
  1429.          */
  1430.         if (p_tf && screen_cur_row == screen_row - 1
  1431. #ifdef USE_GUI
  1432.              && !gui.in_use
  1433. #endif
  1434.                     )
  1435.         {
  1436.         if (screen_cur_col != Columns)
  1437.             screen_char(LinePointers[screen_row - 1] + Columns - 1,
  1438.                       screen_row - 1, (int)(Columns - 1));
  1439.         screen_char(LinePointers[screen_row],
  1440.                         screen_row - 1, (int)Columns);
  1441.         screen_start();        /* don't know where cursor is now */
  1442.         }
  1443.  
  1444.         screenp = current_LinePointer;
  1445. #ifdef RIGHTLEFT
  1446.         if (wp->w_p_rl)
  1447.         {
  1448.         col = Columns - 1;    /* col is not used if breaking! */
  1449.         screenp += Columns - 1;
  1450.         }
  1451. #endif
  1452.     }
  1453.  
  1454.     /*
  1455.      * Store the character.
  1456.      */
  1457.     *screenp = c;
  1458.     *(screenp + Columns) = char_attr;
  1459.  
  1460. #ifdef RIGHTLEFT
  1461.     if (wp->w_p_rl)
  1462.     {
  1463.         --screenp;
  1464.         --col;
  1465.     }
  1466.     else
  1467. #endif
  1468.     {
  1469.         ++screenp;
  1470.         ++col;
  1471.     }
  1472.     ++vcol;
  1473.  
  1474.     /* stop before '$' of change command */
  1475.     if (dollar_vcol && wp == curwin && vcol >= (long)wp->w_virtcol)
  1476.     {
  1477.         SCREEN_LINE(screen_row, col, FALSE, wp->w_p_rl);
  1478.         break;
  1479.     }
  1480.     }
  1481.  
  1482.     return (row);
  1483. }
  1484.  
  1485. /*
  1486.  * Move one "cooked" screen line to the screen, but only the characters that
  1487.  * have actually changed.  Handle insert/delete character.
  1488.  * 'endcol' gives the columns where valid characters are.
  1489.  * 'clear_rest' is TRUE if the rest of the line needs to be cleared.
  1490.  * 'rlflag' is TRUE in a rightleft window:
  1491.  *    When TRUE and clear_rest, line is cleared in 0 -- endcol.
  1492.  *    When FALSE and clear_rest, line is cleared in endcol -- Columns-1.
  1493.  */
  1494.     static void
  1495. screen_line(row, endcol, clear_rest
  1496. #ifdef RIGHTLEFT
  1497.                     , rlflag
  1498. #endif
  1499.                         )
  1500.     int        row;
  1501.     int        endcol;
  1502.     int        clear_rest;
  1503. #ifdef RIGHTLEFT
  1504.     int        rlflag;
  1505. #endif
  1506. {
  1507.     char_u        *screenp_from;
  1508.     char_u        *screenp_to;
  1509.     int            col = 0;
  1510.     int            force = FALSE;    /* force update rest of the line */
  1511.  
  1512.     screenp_from = current_LinePointer;
  1513.     screenp_to = LinePointers[row];
  1514.  
  1515. #ifdef RIGHTLEFT
  1516.     if (rlflag)
  1517.     {
  1518.     if (clear_rest)
  1519.     {
  1520.         while (col <= endcol && *screenp_to == ' '
  1521.                           && *(screenp_to + Columns) == 0)
  1522.         {
  1523.         ++screenp_to;
  1524.         ++col;
  1525.         }
  1526.         if (col <= endcol)
  1527.         screen_fill(row, row + 1, col, endcol + 1, ' ', ' ', 0);
  1528.     }
  1529.     col = endcol + 1;
  1530.     screenp_to = LinePointers[row] + col;
  1531.     screenp_from += col;
  1532.     }
  1533.  
  1534.     while (rlflag ? (col < Columns) : (col < endcol))
  1535. #else
  1536.     while (col < endcol)
  1537. #endif
  1538.     {
  1539.     if (force || *screenp_from != *screenp_to ||
  1540.         *(screenp_from + Columns) != *(screenp_to + Columns))
  1541.     {
  1542.         /*
  1543.          * Special handling when 'xs' termcap flag set (hpterm):
  1544.          * Attributes for characters are stored at the position where the
  1545.          * cursor is when writing the highlighting code.  The
  1546.          * start-highlighting code must be written with the cursor on the
  1547.          * first highlighted character.  The stop-highlighting code must
  1548.          * be written with the cursor just after the last highlighted
  1549.          * character.
  1550.          * Overwriting a character doesn't remove it's highlighting.  Need
  1551.          * to clear the rest of the line, and force redrawing it
  1552.          * completely.
  1553.          */
  1554.         if (       p_wiv
  1555.             && !force
  1556. #ifdef USE_GUI
  1557.             && !gui.in_use
  1558. #endif
  1559.             && *(screenp_to + Columns)
  1560.             && *(screenp_from + Columns) != *(screenp_to + Columns))
  1561.         {
  1562.         /*
  1563.          * Need to remove highlighting attributes here.
  1564.          */
  1565.         windgoto(row, col);
  1566.         out_str(T_CE);        /* clear rest of this screen line */
  1567.         screen_start();        /* don't know where cursor is now */
  1568.         force = TRUE;        /* force redraw of rest of the line */
  1569.  
  1570.         /*
  1571.          * If the previous character was highlighted, need to stop
  1572.          * highlighting at this character.
  1573.          */
  1574.         if (col > 0 && *(screenp_to + Columns - 1))
  1575.         {
  1576.             screen_attr = *(screenp_to + Columns - 1);
  1577.             term_windgoto(row, col);
  1578.             screen_stop_highlight();
  1579.         }
  1580.         else
  1581.             screen_attr = 0;        /* highlighting has stopped */
  1582.         }
  1583.         *screenp_to = *screenp_from;
  1584.  
  1585. #if defined(USE_GUI) || defined(UNIX)
  1586.         /* The bold trick makes a single row of pixels appear in the next
  1587.          * character.  When a bold character is removed, the next
  1588.          * character should be redrawn too.  This happens for our own GUI
  1589.          * and for some xterms. */
  1590.         if (
  1591. # ifdef USE_GUI
  1592.             gui.in_use
  1593. # endif
  1594. # if defined(USE_GUI) && defined(UNIX)
  1595.             ||
  1596. # endif
  1597. # ifdef UNIX
  1598.             vim_is_xterm(T_NAME)
  1599. # endif
  1600.             )
  1601.         {
  1602.         int        n;
  1603.  
  1604.         n = *(screenp_to + Columns);
  1605.         if (col + 1 < Columns && (n > HL_ALL || (n & HL_BOLD)))
  1606.             *(screenp_to + 1) = 0;
  1607.         }
  1608. #endif
  1609.         *(screenp_to + Columns) = *(screenp_from + Columns);
  1610.         screen_char(screenp_to, row, col);
  1611.     }
  1612.     else if (  p_wiv
  1613. #ifdef USE_GUI
  1614.         && !gui.in_use
  1615. #endif
  1616.         && col > 0)
  1617.     {
  1618.         if (*(screenp_to + Columns) == *(screenp_to + Columns - 1))
  1619.         {
  1620.         /*
  1621.          * Don't output stop-highlight when moving the cursor, it will
  1622.          * stop the highlighting when it should continue.
  1623.          */
  1624.         screen_attr = 0;
  1625.         }
  1626.         else if (screen_attr)
  1627.         {
  1628.         screen_stop_highlight();
  1629.         }
  1630.     }
  1631.  
  1632.     ++screenp_to;
  1633.     ++screenp_from;
  1634.     ++col;
  1635.     }
  1636.  
  1637.     if (clear_rest
  1638. #ifdef RIGHTLEFT
  1639.             && !rlflag
  1640. #endif
  1641.                    )
  1642.     {
  1643.     /* blank out the rest of the line */
  1644.     while (col < Columns && *screenp_to == ' ' &&
  1645.         *(screenp_to + Columns) == 0)
  1646.     {
  1647.         ++screenp_to;
  1648.         ++col;
  1649.     }
  1650.     if (col < Columns)
  1651.         screen_fill(row, row + 1, col, (int)Columns, ' ', ' ', 0);
  1652.     }
  1653. }
  1654.  
  1655. /*
  1656.  * mark all status lines for redraw; used after first :cd
  1657.  */
  1658.     void
  1659. status_redraw_all()
  1660. {
  1661.     WIN        *wp;
  1662.  
  1663.     for (wp = firstwin; wp; wp = wp->w_next)
  1664.     if (wp->w_status_height)
  1665.     {
  1666.         wp->w_redr_status = TRUE;
  1667.         redraw_later(NOT_VALID);
  1668.     }
  1669. }
  1670.  
  1671. /*
  1672.  * Redraw the status line of window wp.
  1673.  *
  1674.  * If inversion is possible we use it. Else '=' characters are used.
  1675.  */
  1676.     void
  1677. win_redr_status(wp)
  1678.     WIN        *wp;
  1679. {
  1680.     int        row;
  1681.     char_u  *p;
  1682.     int        len;
  1683.     int        fillchar;
  1684.     int        attr;
  1685.  
  1686.     if (wp->w_status_height)            /* if there is a status line */
  1687.     {
  1688.     fillchar = highlight_status(&attr, wp == curwin);
  1689.  
  1690.     p = wp->w_buffer->b_fname;
  1691.     if (p == NULL)
  1692.         STRCPY(NameBuff, "[No File]");
  1693.     else
  1694.     {
  1695.         home_replace(wp->w_buffer, p, NameBuff, MAXPATHL);
  1696.         trans_characters(NameBuff, MAXPATHL);
  1697.     }
  1698.     p = NameBuff;
  1699.     len = STRLEN(p);
  1700.  
  1701.     if (wp->w_buffer->b_help || buf_changed(wp->w_buffer) ||
  1702.                              wp->w_buffer->b_p_ro)
  1703.         *(p + len++) = ' ';
  1704.     if (wp->w_buffer->b_help)
  1705.     {
  1706.         STRCPY(p + len, "[help]");
  1707.         len += 6;
  1708.     }
  1709.     if (buf_changed(wp->w_buffer))
  1710.     {
  1711.         STRCPY(p + len, "[+]");
  1712.         len += 3;
  1713.     }
  1714.     if (wp->w_buffer->b_p_ro)
  1715.     {
  1716.         STRCPY(p + len, "[RO]");
  1717.         len += 4;
  1718.     }
  1719.  
  1720.     if (len > ru_col - 1)
  1721.     {
  1722.         p += len - (ru_col - 1);
  1723.         *p = '<';
  1724.         len = ru_col - 1;
  1725.     }
  1726.  
  1727.     row = wp->w_winpos + wp->w_height;
  1728.     screen_puts(p, row, 0, attr);
  1729.     screen_fill(row, row + 1, len, ru_col, fillchar, fillchar, attr);
  1730.  
  1731.     win_redr_ruler(wp, TRUE);
  1732.     }
  1733.     else    /* no status line, can only be last window */
  1734.     redraw_cmdline = TRUE;
  1735.     wp->w_redr_status = FALSE;
  1736. }
  1737.  
  1738. /*
  1739.  * Output a single character directly to the screen and update NextScreen.
  1740.  */
  1741.     void
  1742. screen_putchar(c, row, col, attr)
  1743.     int        c;
  1744.     int        row, col;
  1745.     int        attr;
  1746. {
  1747.     char_u    buf[2];
  1748.  
  1749.     buf[0] = c;
  1750.     buf[1] = NUL;
  1751.     screen_puts(buf, row, col, attr);
  1752. }
  1753.  
  1754. /*
  1755.  * Put string '*text' on the screen at position 'row' and 'col', with
  1756.  * attributes 'attr', and update NextScreen.
  1757.  * Note: only outputs within one row, message is truncated at screen boundary!
  1758.  * Note: if NextScreen, row and/or col is invalid, nothing is done.
  1759.  */
  1760.     void
  1761. screen_puts(text, row, col, attr)
  1762.     char_u  *text;
  1763.     int        row;
  1764.     int        col;
  1765.     int        attr;
  1766. {
  1767.     char_u  *screenp;
  1768.  
  1769.     if (NextScreen != NULL && row < Rows)        /* safety check */
  1770.     {
  1771.     screenp = LinePointers[row] + col;
  1772.     while (*text && col < Columns)
  1773.     {
  1774.         if (*screenp != *text || *(screenp + Columns) != attr ||
  1775.                                 exmode_active)
  1776.         {
  1777.         *screenp = *text;
  1778.         *(screenp + Columns) = attr;
  1779.         screen_char(screenp, row, col);
  1780.         }
  1781.         ++screenp;
  1782.         ++col;
  1783.         ++text;
  1784.     }
  1785.     }
  1786. }
  1787.  
  1788. #ifdef EXTRA_SEARCH
  1789. /*
  1790.  * Prepare for 'searchhl' highlighting.
  1791.  */
  1792.     static void
  1793. start_search_hl()
  1794. {
  1795.     if (p_hls)
  1796.     {
  1797.     search_hl_prog = last_pat_prog();
  1798.     search_hl_attr = highlight_attr[HLF_L];
  1799.     search_hl_ic = reg_ic;
  1800.     }
  1801. }
  1802.  
  1803. /*
  1804.  * Clean up for 'searchhl' highlighting.
  1805.  */
  1806.     static void
  1807. end_search_hl()
  1808. {
  1809.     if (search_hl_prog != NULL)
  1810.     {
  1811.     vim_free(search_hl_prog);
  1812.     search_hl_prog = NULL;
  1813.     }
  1814. }
  1815. #endif
  1816.  
  1817. /*
  1818.  * Reset cursor position. Use whenever cursor was moved because of outputting
  1819.  * something directly to the screen (shell commands) or a terminal control
  1820.  * code.
  1821.  */
  1822.     void
  1823. screen_start()
  1824. {
  1825.     screen_cur_row = screen_cur_col = 9999;
  1826. }
  1827.  
  1828. /*
  1829.  * Note that the cursor has gone down to the next line, column 0.
  1830.  * Used for Ex mode.
  1831.  */
  1832.     void
  1833. screen_down()
  1834. {
  1835.     screen_cur_col = 0;
  1836.     if (screen_cur_row < Rows - 1)
  1837.     ++screen_cur_row;
  1838. }
  1839.  
  1840.       static void
  1841. screen_start_highlight(attr)
  1842.       int    attr;
  1843. {
  1844.     struct attr_entry *aep = NULL;
  1845.  
  1846.     screen_attr = attr;
  1847.     if (full_screen
  1848. #ifdef WIN32
  1849.             && termcap_active
  1850. #endif
  1851.                        )
  1852.     {
  1853. #ifdef USE_GUI
  1854.     if (gui.in_use)
  1855.     {
  1856.         char    buf[20];
  1857.  
  1858.         sprintf(buf, "\033|%dh", attr);        /* internal GUI code */
  1859.         OUT_STR(buf);
  1860.     }
  1861.     else
  1862. #endif
  1863.     {
  1864.         if (attr > HL_ALL)                /* special HL attr. */
  1865.         {
  1866.         if (*T_CCO != NUL)
  1867.             aep = syn_cterm_attr2entry(attr);
  1868.         else
  1869.             aep = syn_term_attr2entry(attr);
  1870.         if (aep == NULL)        /* did ":syntax clear" */
  1871.             attr = 0;
  1872.         else
  1873.             attr = aep->ae_attr;
  1874.         }
  1875.         if ((attr & HL_BOLD) && T_MD != NULL)    /* bold */
  1876.         out_str(T_MD);
  1877.         if ((attr & HL_STANDOUT) && T_SO != NULL)    /* standout */
  1878.         out_str(T_SO);
  1879.         if ((attr & HL_UNDERLINE) && T_US != NULL)    /* underline */
  1880.         out_str(T_US);
  1881.         if ((attr & HL_ITALIC) && T_CZH != NULL)    /* italic */
  1882.         out_str(T_CZH);
  1883.         if ((attr & HL_INVERSE) && T_MR != NULL)    /* inverse (reverse) */
  1884.         out_str(T_MR);
  1885.  
  1886.         /*
  1887.          * Output the color or start string after bold etc., in case the
  1888.          * bold etc. override the color setting.
  1889.          */
  1890.         if (aep != NULL)
  1891.         {
  1892.         if (*T_CCO != NUL)
  1893.         {
  1894.             if (aep->ae_u.cterm.fg_color)
  1895.             term_fg_color(aep->ae_u.cterm.fg_color - 1);
  1896.             if (aep->ae_u.cterm.bg_color)
  1897.             term_bg_color(aep->ae_u.cterm.bg_color - 1);
  1898.         }
  1899.         else
  1900.         {
  1901.             if (aep->ae_u.term.start != NULL)
  1902.             out_str(aep->ae_u.term.start);
  1903.         }
  1904.         }
  1905.     }
  1906.     }
  1907. }
  1908.  
  1909.       void
  1910. screen_stop_highlight()
  1911. {
  1912.     int        do_ME = FALSE;        /* output T_ME code */
  1913.  
  1914.     if (screen_attr
  1915. #ifdef WIN32
  1916.             && termcap_active
  1917. #endif
  1918.                        )
  1919.     {
  1920. #ifdef USE_GUI
  1921.     if (gui.in_use)
  1922.     {
  1923.         char    buf[20];
  1924.  
  1925.         sprintf(buf, "\033|%dH", screen_attr);    /* internal GUI code */
  1926.         OUT_STR(buf);
  1927.     }
  1928.     else
  1929. #endif
  1930.     {
  1931.         if (screen_attr > HL_ALL)            /* special HL attr. */
  1932.         {
  1933.         struct attr_entry *aep;
  1934.  
  1935.         if (*T_CCO != NUL)
  1936.         {
  1937.             /*
  1938.              * Assume that t_me restores the original colors!
  1939.              */
  1940.             aep = syn_cterm_attr2entry(screen_attr);
  1941.             if (aep != NULL && (aep->ae_u.cterm.fg_color ||
  1942.                             aep->ae_u.cterm.bg_color))
  1943.             do_ME = TRUE;
  1944.         }
  1945.         else
  1946.         {
  1947.             aep = syn_term_attr2entry(screen_attr);
  1948.             if (aep != NULL && aep->ae_u.term.stop != NULL)
  1949.             {
  1950.             if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
  1951.                 do_ME = TRUE;
  1952.             else
  1953.                 out_str(aep->ae_u.term.stop);
  1954.             }
  1955.         }
  1956.         if (aep == NULL)        /* did ":syntax clear" */
  1957.             screen_attr = 0;
  1958.         else
  1959.             screen_attr = aep->ae_attr;
  1960.         }
  1961.  
  1962.         /*
  1963.          * Often all ending-codes are equal to T_ME.  Avoid outputting the
  1964.          * same sequence several times.
  1965.          */
  1966.         if (screen_attr & HL_STANDOUT)
  1967.         {
  1968.         if (STRCMP(T_SE, T_ME) == 0)
  1969.             do_ME = TRUE;
  1970.         else
  1971.             out_str(T_SE);
  1972.         }
  1973.         if (screen_attr & HL_UNDERLINE)
  1974.         {
  1975.         if (STRCMP(T_UE, T_ME) == 0)
  1976.             do_ME = TRUE;
  1977.         else
  1978.             out_str(T_UE);
  1979.         }
  1980.         if (screen_attr & HL_ITALIC)
  1981.         {
  1982.         if (STRCMP(T_CZR, T_ME) == 0)
  1983.             do_ME = TRUE;
  1984.         else
  1985.             out_str(T_CZR);
  1986.         }
  1987.         if (do_ME || (screen_attr & HL_BOLD) || (screen_attr & HL_INVERSE))
  1988.         out_str(T_ME);
  1989.  
  1990.         if (*T_CCO != NUL)
  1991.         {
  1992.         /* set Normal cterm colors */
  1993.         if (cterm_normal_fg_color)
  1994.             term_fg_color(cterm_normal_fg_color - 1);
  1995.         if (cterm_normal_bg_color)
  1996.             term_bg_color(cterm_normal_bg_color - 1);
  1997.         if (cterm_normal_fg_bold)
  1998.             out_str(T_MD);
  1999.         }
  2000.     }
  2001.     }
  2002.     screen_attr = 0;
  2003. }
  2004.  
  2005. /*
  2006.  * Reset the colors for a cterm.  Used when leaving Vim.
  2007.  */
  2008.     void
  2009. reset_cterm_colors()
  2010. {
  2011.     if (*T_CCO != NUL)
  2012.     {
  2013.     /* set Normal cterm colors */
  2014.     if (cterm_normal_fg_color || cterm_normal_bg_color)
  2015.         out_str(T_OP);
  2016.     if (cterm_normal_fg_bold)
  2017.         out_str(T_ME);
  2018.     }
  2019. }
  2020.  
  2021. /*
  2022.  * put character '*p' on the screen at position 'row' and 'col'
  2023.  */
  2024.     static void
  2025. screen_char(p, row, col)
  2026.     char_u  *p;
  2027.     int        row;
  2028.     int        col;
  2029. {
  2030.     /*
  2031.      * Outputting the last character on the screen may scrollup the screen.
  2032.      * Don't to it!
  2033.      */
  2034.     if (col == Columns - 1 && row == Rows - 1)
  2035.     return;
  2036.  
  2037.     /*
  2038.      * Stop highlighting first, so it's easier to move the cursor.
  2039.      */
  2040.     if (screen_attr != *(p + Columns))
  2041.     screen_stop_highlight();
  2042.  
  2043.     windgoto(row, col);
  2044.  
  2045.     if (screen_attr != *(p + Columns))
  2046.     screen_start_highlight(*(p + Columns));
  2047.  
  2048.     out_char(*p);
  2049.     screen_cur_col++;
  2050. }
  2051.  
  2052. /*
  2053.  * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
  2054.  * with character 'c1' in first column followed by 'c2' in the other columns.
  2055.  * Use attributes 'attr'.
  2056.  */
  2057.     void
  2058. screen_fill(start_row, end_row, start_col, end_col, c1, c2, attr)
  2059.     int        start_row, end_row;
  2060.     int        start_col, end_col;
  2061.     int        c1, c2;
  2062.     int        attr;
  2063. {
  2064.     int            row;
  2065.     int            col;
  2066.     char_u        *screenp;
  2067.     char_u        *attrp;
  2068.     int            did_delete;
  2069.     int            c;
  2070.     int            norm_term;
  2071.  
  2072.     if (end_row > Rows)            /* safety check */
  2073.     end_row = Rows;
  2074.     if (end_col > Columns)        /* safety check */
  2075.     end_col = Columns;
  2076.     if (NextScreen == NULL ||
  2077.         start_row >= end_row || start_col >= end_col)   /* nothing to do */
  2078.     return;
  2079.  
  2080.     /* it's a "normal" terminal when not in a GUI or cterm */
  2081.     norm_term = (
  2082. #ifdef USE_GUI
  2083.         !gui.in_use &&
  2084. #endif
  2085.                 *T_CCO == NUL);
  2086.     for (row = start_row; row < end_row; ++row)
  2087.     {
  2088.     /*
  2089.      * Try to use delete-line termcap code, when no attributes or in a
  2090.      * "normal" terminal, where a bold/italic space is just a
  2091.      * space.
  2092.      */
  2093.     did_delete = FALSE;
  2094.     if (c2 == ' ' && end_col == Columns && *T_CE != NUL
  2095.         && (attr == 0 || (norm_term && attr <= HL_ALL
  2096.             && ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
  2097.     {
  2098.         /*
  2099.          * check if we really need to clear something
  2100.          */
  2101.         col = start_col;
  2102.         screenp = LinePointers[row] + start_col;
  2103.         if (c1 != ' ')            /* don't clear first char */
  2104.         {
  2105.         ++col;
  2106.         ++screenp;
  2107.         }
  2108.  
  2109.         /* skip blanks (used often, keep it fast!) */
  2110.         attrp = screenp + Columns;
  2111.         while (col < end_col && *screenp == ' ' && *attrp == 0)
  2112.         {
  2113.         ++col;
  2114.         ++screenp;
  2115.         ++attrp;
  2116.         }
  2117.         if (col < end_col)        /* something to be cleared */
  2118.         {
  2119.         screen_stop_highlight();
  2120.         term_windgoto(row, col);/* clear rest of this screen line */
  2121.         out_str(T_CE);
  2122.         screen_start();        /* don't know where cursor is now */
  2123.         col = end_col - col;
  2124.         while (col--)        /* clear chars in NextScreen */
  2125.         {
  2126.             *attrp++ = 0;
  2127.             *screenp++ = ' ';
  2128.         }
  2129.         }
  2130.         did_delete = TRUE;        /* the chars are cleared now */
  2131.     }
  2132.  
  2133.     screenp = LinePointers[row] + start_col;
  2134.     c = c1;
  2135.     for (col = start_col; col < end_col; ++col)
  2136.     {
  2137.         if (*screenp != c || *(screenp + Columns) != attr)
  2138.         {
  2139.         *screenp = c;
  2140.         *(screenp + Columns) = attr;
  2141.         if (!did_delete || c != ' ')
  2142.             screen_char(screenp, row, col);
  2143.         }
  2144.         ++screenp;
  2145.         if (col == start_col)
  2146.         {
  2147.         if (did_delete)
  2148.             break;
  2149.         c = c2;
  2150.         }
  2151.     }
  2152.     if (row == Rows - 1)        /* overwritten the command line */
  2153.     {
  2154.         redraw_cmdline = TRUE;
  2155.         if (c1 == ' ' && c2 == ' ')
  2156.         clear_cmdline = FALSE;    /* command line has been cleared */
  2157.     }
  2158.     }
  2159. }
  2160.  
  2161. /*
  2162.  * compute wp->w_botline. Can be called after wp->w_topline changed.
  2163.  */
  2164.     static void
  2165. comp_botline()
  2166. {
  2167.     int        n;
  2168.     linenr_t    lnum;
  2169.     int        done;
  2170.  
  2171.     /*
  2172.      * If w_cline_row is valid, start there.
  2173.      * Otherwise have to start at w_topline.
  2174.      */
  2175.     check_cursor_moved(curwin);
  2176.     if (curwin->w_valid & VALID_CROW)
  2177.     {
  2178.     lnum = curwin->w_cursor.lnum;
  2179.     done = curwin->w_cline_row;
  2180.     }
  2181.     else
  2182.     {
  2183.     lnum = curwin->w_topline;
  2184.     done = 0;
  2185.     }
  2186.  
  2187.     for ( ; lnum <= curwin->w_buffer->b_ml.ml_line_count; ++lnum)
  2188.     {
  2189.     n = plines(lnum);
  2190.     if (lnum == curwin->w_cursor.lnum)
  2191.     {
  2192.         curwin->w_cline_row = done;
  2193.         curwin->w_cline_height = n;
  2194.         curwin->w_valid |= (VALID_CROW|VALID_CHEIGHT);
  2195.     }
  2196.     if (done + n > curwin->w_height)
  2197.         break;
  2198.     done += n;
  2199.     }
  2200.  
  2201.     /* curwin->w_botline is the line that is just below the window */
  2202.     curwin->w_botline = lnum;
  2203.     curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  2204.  
  2205.     /*
  2206.      * Also set curwin->w_empty_rows, otherwise scroll_cursor_bot() won't work
  2207.      */
  2208.     if (done == 0)
  2209.     curwin->w_empty_rows = 0;    /* single line that doesn't fit */
  2210.     else
  2211.     curwin->w_empty_rows = curwin->w_height - done;
  2212. }
  2213.  
  2214.     void
  2215. screenalloc(clear)
  2216.     int        clear;
  2217. {
  2218.     int            new_row, old_row;
  2219.     WIN            *wp;
  2220.     int            outofmem = FALSE;
  2221.     int            len;
  2222.     char_u        *new_NextScreen;
  2223.     char_u        **new_LinePointers;
  2224.     static int        entered = FALSE;        /* avoid recursiveness */
  2225.  
  2226.     /*
  2227.      * Allocation of the screen buffers is done only when the size changes
  2228.      * and when Rows and Columns have been set and we have started doing full
  2229.      * screen stuff.
  2230.      */
  2231.     if ((NextScreen != NULL &&
  2232.               Rows == screen_Rows && Columns == screen_Columns) ||
  2233.         Rows == 0 || Columns == 0 || (!full_screen && NextScreen == NULL))
  2234.     return;
  2235.  
  2236.     /*
  2237.      * It's possible that we produce an out-of-memory message below, which
  2238.      * will cause this function to be called again.  To break the loop, just
  2239.      * return here.
  2240.      */
  2241.     if (entered)
  2242.     return;
  2243.     entered = TRUE;
  2244.  
  2245. #ifdef USE_GUI_BEOS
  2246.     vim_lock_screen();  /* be safe, put it here */
  2247. #endif
  2248.  
  2249.     comp_col();        /* recompute columns for shown command and ruler */
  2250.  
  2251.     /*
  2252.      * We're changing the size of the screen.
  2253.      * - Allocate new arrays for NextScreen.
  2254.      * - Move lines from the old arrays into the new arrays, clear extra
  2255.      *     lines (unless the screen is going to be cleared).
  2256.      * - Free the old arrays.
  2257.      *
  2258.      * If anything fails, make NextScreen NULL, so we don't do anything!
  2259.      * Continuing with the old NextScreen may result in a crash, because the
  2260.      * size is wrong.
  2261.      */
  2262.     for (wp = firstwin; wp; wp = wp->w_next)
  2263.     win_free_lsize(wp);
  2264.  
  2265.     new_NextScreen = (char_u *)malloc((size_t)((Rows + 1) * Columns * 2));
  2266.     new_LinePointers = (char_u **)malloc((size_t)(sizeof(char_u *) * Rows));
  2267.  
  2268.     for (wp = firstwin; wp; wp = wp->w_next)
  2269.     {
  2270.     if (win_alloc_lsize(wp) == FAIL)
  2271.     {
  2272.         outofmem = TRUE;
  2273.         break;
  2274.     }
  2275.     }
  2276.  
  2277.     if (new_NextScreen == NULL || new_LinePointers == NULL || outofmem)
  2278.     {
  2279.     do_outofmem_msg();
  2280.     vim_free(new_NextScreen);
  2281.     new_NextScreen = NULL;
  2282.     vim_free(new_LinePointers);
  2283.     new_LinePointers = NULL;
  2284.     }
  2285.     else
  2286.     {
  2287.     for (new_row = 0; new_row < Rows; ++new_row)
  2288.     {
  2289.         new_LinePointers[new_row] = new_NextScreen + new_row * Columns * 2;
  2290.  
  2291.         /*
  2292.          * If the screen is not going to be cleared, copy as much as
  2293.          * possible from the old screen to the new one and clear the rest
  2294.          * (used when resizing the window at the "--more--" prompt or when
  2295.          * executing an external command, for the GUI).
  2296.          */
  2297.         if (!clear)
  2298.         {
  2299.         lineclear(new_LinePointers[new_row]);
  2300.         old_row = new_row + (screen_Rows - Rows);
  2301.         if (old_row >= 0)
  2302.         {
  2303.             if (screen_Columns < Columns)
  2304.             len = screen_Columns;
  2305.             else
  2306.             len = Columns;
  2307.             vim_memmove(new_LinePointers[new_row],
  2308.                 LinePointers[old_row], (size_t)len);
  2309.             vim_memmove(new_LinePointers[new_row] + Columns,
  2310.                 LinePointers[old_row] + screen_Columns,
  2311.                                  (size_t)len);
  2312.         }
  2313.         }
  2314.     }
  2315.     current_LinePointer = new_NextScreen + Rows * Columns * 2;
  2316.     }
  2317.  
  2318.     vim_free(NextScreen);
  2319.     vim_free(LinePointers);
  2320.     NextScreen = new_NextScreen;
  2321.     LinePointers = new_LinePointers;
  2322.  
  2323.     must_redraw = CLEAR;    /* need to clear the screen later */
  2324.     if (clear)
  2325.     screenclear2();
  2326.  
  2327. #ifdef USE_GUI
  2328.     else if (gui.in_use && NextScreen != NULL && Rows != screen_Rows)
  2329.     {
  2330.     (void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
  2331.     /*
  2332.      * Adjust the position of the cursor, for when executing an external
  2333.      * command.
  2334.      */
  2335.     if (msg_row >= Rows)            /* Rows got smaller */
  2336.         msg_row = Rows - 1;            /* put cursor at last row */
  2337.     else if (Rows > screen_Rows)        /* Rows got bigger */
  2338.         msg_row += Rows - screen_Rows;  /* put cursor in same place */
  2339.     if (msg_col >= Columns)            /* Columns got smaller */
  2340.         msg_col = Columns - 1;        /* put cursor at last column */
  2341.     }
  2342. #endif
  2343.  
  2344.     screen_Rows = Rows;
  2345.     screen_Columns = Columns;
  2346. #ifdef USE_GUI_BEOS
  2347.     vim_unlock_screen();
  2348. #endif
  2349.     entered = FALSE;
  2350. }
  2351.  
  2352.     void
  2353. screenclear()
  2354. {
  2355.     check_for_delay(FALSE);
  2356.     screenalloc(FALSE);        /* allocate screen buffers if size changed */
  2357.     screenclear2();        /* clear the screen */
  2358. }
  2359.  
  2360.     static void
  2361. screenclear2()
  2362. {
  2363.     int        i;
  2364.  
  2365.     if (starting || NextScreen == NULL)
  2366.     return;
  2367.  
  2368.     screen_stop_highlight();    /* don't want highlighting here */
  2369.     out_str(T_CL);        /* clear the display */
  2370.  
  2371.                 /* blank out NextScreen */
  2372.     for (i = 0; i < Rows; ++i)
  2373.     lineclear(LinePointers[i]);
  2374.  
  2375.     screen_cleared = TRUE;        /* can use contents of NextScreen now */
  2376.  
  2377.     win_rest_invalid(firstwin);
  2378.     clear_cmdline = FALSE;
  2379.     redraw_cmdline = TRUE;
  2380.     if (must_redraw == CLEAR)        /* no need to clear again */
  2381.     must_redraw = NOT_VALID;
  2382.     compute_cmdrow();
  2383.     msg_row = cmdline_row;        /* put cursor on last line for messages */
  2384.     msg_col = 0;
  2385.     screen_start();            /* don't know where cursor is now */
  2386.     msg_scrolled = 0;            /* can't scroll back */
  2387.     msg_didany = FALSE;
  2388.     msg_didout = FALSE;
  2389. }
  2390.  
  2391. /*
  2392.  * Clear one line in NextScreen.
  2393.  */
  2394.     static void
  2395. lineclear(p)
  2396.     char_u  *p;
  2397. {
  2398.     (void)vim_memset(p, ' ', (size_t)Columns);
  2399.     (void)vim_memset(p + Columns, 0, (size_t)Columns);
  2400. }
  2401.  
  2402. /*
  2403.  * Update curwin->w_topline and redraw if necessary.
  2404.  */
  2405.     void
  2406. update_topline_redraw()
  2407. {
  2408.     update_topline();
  2409.     if (must_redraw)
  2410.     update_screen(must_redraw);
  2411. }
  2412.  
  2413. /*
  2414.  * Update curwin->w_topline to move the cursor onto the screen.
  2415.  */
  2416.     void
  2417. update_topline()
  2418. {
  2419.     long        line_count;
  2420.     int            temp;
  2421.     linenr_t        old_topline;
  2422.  
  2423.     if (!screen_valid(TRUE))
  2424.     return;
  2425.  
  2426.     old_topline = curwin->w_topline;
  2427.  
  2428.     /*
  2429.      * If the buffer is empty, always set topline to 1.
  2430.      */
  2431.     if (bufempty())        /* special case - file is empty */
  2432.     {
  2433.     if (curwin->w_topline != 1)
  2434.         redraw_later(NOT_VALID);
  2435.     curwin->w_topline = 1;
  2436.     curwin->w_botline = 2;
  2437.     curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  2438.     }
  2439.  
  2440.     /*
  2441.      * If the cursor is above the top of the window, scroll the window to put
  2442.      * it at the top of the window.
  2443.      * If we weren't very close to begin with, we scroll to put the cursor in
  2444.      * the middle of the window.
  2445.      */
  2446.     else if (curwin->w_cursor.lnum < curwin->w_topline + p_so &&
  2447.                             curwin->w_topline > 1)
  2448.     {
  2449.     temp = curwin->w_height / 2 - 1;
  2450.     if (temp < 2)
  2451.         temp = 2;
  2452.                 /* not very close, put cursor halfway screen */
  2453.     if (curwin->w_topline + p_so - curwin->w_cursor.lnum >= temp)
  2454.         scroll_cursor_halfway(FALSE);
  2455.     else
  2456.         scroll_cursor_top((int)p_sj, FALSE);
  2457.     }
  2458.  
  2459.     /*
  2460.      * If the cursor is below the bottom of the window, scroll the window
  2461.      * to put the cursor on the window. If the cursor is less than a
  2462.      * windowheight down compute the number of lines at the top which have
  2463.      * the same or more rows than the rows of the lines below the bottom.
  2464.      * When w_botline is invalid, recompute it first, to avoid a redraw later.
  2465.      * If w_botline was approximated, we might need a redraw later in a few
  2466.      * cases, but we don't want to spend (a lot of) time recomputing w_botline
  2467.      * for every small change.
  2468.      */
  2469.     else
  2470.     {
  2471.     if (!(curwin->w_valid & VALID_BOTLINE_AP))
  2472.         validate_botline();
  2473.     if ((long)curwin->w_cursor.lnum >= (long)curwin->w_botline - p_so &&
  2474.         curwin->w_botline <= curbuf->b_ml.ml_line_count)
  2475.     {
  2476.         line_count = curwin->w_cursor.lnum - curwin->w_botline + 1 + p_so;
  2477.         if (line_count <= curwin->w_height + 1)
  2478.         scroll_cursor_bot((int)p_sj, FALSE);
  2479.         else
  2480.         scroll_cursor_halfway(FALSE);
  2481.     }
  2482.     }
  2483.  
  2484.     /*
  2485.      * Need to redraw when topline changed.
  2486.      */
  2487.     if (curwin->w_topline != old_topline)
  2488.     redraw_later(VALID);
  2489. }
  2490.  
  2491.     void
  2492. update_curswant()
  2493. {
  2494.     if (curwin->w_set_curswant)
  2495.     {
  2496.     validate_virtcol();
  2497.     curwin->w_curswant = curwin->w_virtcol;
  2498.     curwin->w_set_curswant = FALSE;
  2499.     }
  2500. }
  2501.  
  2502.     void
  2503. windgoto(row, col)
  2504.     int        row;
  2505.     int        col;
  2506. {
  2507.     char_u        *p;
  2508.     int            i;
  2509.     int            plan;
  2510.     int            cost;
  2511.     int            wouldbe_col;
  2512.     int            noinvcurs;
  2513.     char_u        *bs;
  2514.     int            goto_cost;
  2515.     int            attr;
  2516.  
  2517. #define GOTO_COST   7    /* asssume a term_windgoto() takes about 7 chars */
  2518. #define HIGHL_COST  5    /* assume unhighlight takes 5 chars */
  2519.  
  2520. #define PLAN_LE        1
  2521. #define PLAN_CR        2
  2522. #define PLAN_NL        3
  2523. #define PLAN_WRITE  4
  2524.  
  2525.     if (col != screen_cur_col || row != screen_cur_row)
  2526.     {
  2527.     /* check if no cursor movement is allowed in highlight mode */
  2528.     if (screen_attr && *T_MS == NUL)
  2529.         noinvcurs = HIGHL_COST;
  2530.     else
  2531.         noinvcurs = 0;
  2532.     goto_cost = GOTO_COST + noinvcurs;
  2533.  
  2534.     /*
  2535.      * Plan how to do the positioning:
  2536.      * 1. Use CR to move it to column 0, same row.
  2537.      * 2. Use T_LE to move it a few columns to the left.
  2538.      * 3. Use NL to move a few lines down, column 0.
  2539.      * 4. Move a few columns to the right with T_ND or by writing chars.
  2540.      *
  2541.      * Don't do this if the cursor went beyond the last column, the cursor
  2542.      * position is unknown then (some terminals wrap, some don't )
  2543.      *
  2544.      * First check if the highlighting attibutes allow us to write
  2545.      * characters to move the cursor to the right.
  2546.      */
  2547.     if (row >= screen_cur_row && screen_cur_col < Columns)
  2548.     {
  2549.         /*
  2550.          * If the cursor is in the same row, bigger col, we can use CR
  2551.          * or T_LE.
  2552.          */
  2553.         bs = NULL;                /* init for GCC */
  2554.         attr = screen_attr;
  2555.         if (row == screen_cur_row && col < screen_cur_col)
  2556.         {
  2557.         /* "le" is preferred over "bc", because "bc" is obsolete */
  2558.         if (*T_LE)
  2559.             bs = T_LE;            /* "cursor left" */
  2560.         else
  2561.             bs = T_BC;            /* "backspace character (old) */
  2562.         if (*bs)
  2563.             cost = (screen_cur_col - col) * STRLEN(bs);
  2564.         else
  2565.             cost = 999;
  2566.         if (col + 1 < cost)        /* using CR is less characters */
  2567.         {
  2568.             plan = PLAN_CR;
  2569.             wouldbe_col = 0;
  2570.             cost = 1;            /* CR is just one character */
  2571.         }
  2572.         else
  2573.         {
  2574.             plan = PLAN_LE;
  2575.             wouldbe_col = col;
  2576.         }
  2577.         if (noinvcurs)            /* will stop highlighting */
  2578.         {
  2579.             cost += noinvcurs;
  2580.             attr = 0;
  2581.         }
  2582.         }
  2583.  
  2584.         /*
  2585.          * If the cursor is above where we want to be, we can use CR LF.
  2586.          */
  2587.         else if (row > screen_cur_row)
  2588.         {
  2589.         plan = PLAN_NL;
  2590.         wouldbe_col = 0;
  2591.         cost = (row - screen_cur_row) * 2;  /* CR LF */
  2592.         if (noinvcurs)            /* will stop highlighting */
  2593.         {
  2594.             cost += noinvcurs;
  2595.             attr = 0;
  2596.         }
  2597.         }
  2598.  
  2599.         /*
  2600.          * If the cursor is in the same row, smaller col, just use write.
  2601.          */
  2602.         else
  2603.         {
  2604.         plan = PLAN_WRITE;
  2605.         wouldbe_col = screen_cur_col;
  2606.         cost = 0;
  2607.         }
  2608.  
  2609.         /*
  2610.          * Check if any characters that need to be written have the
  2611.          * correct attributes.
  2612.          */
  2613.         i = col - wouldbe_col;
  2614.         if (i > 0)
  2615.         cost += i;
  2616.         if (cost < goto_cost && i > 0)
  2617.         {
  2618.         /*
  2619.          * Check if the attributes are correct without additionally
  2620.          * stopping highlighting.
  2621.          */
  2622.         p = LinePointers[row] + wouldbe_col + Columns;
  2623.         while (i && *p++ == attr)
  2624.             --i;
  2625.         if (i)
  2626.         {
  2627.             /*
  2628.              * Try if it works when highlighting is stopped here.
  2629.              */
  2630.             if (*--p == 0)
  2631.             {
  2632.             cost += noinvcurs;
  2633.             while (i && *p++ == 0)
  2634.                 --i;
  2635.             }
  2636.             if (i)
  2637.             cost = 999;    /* different attributes, don't do it */
  2638.         }
  2639.         }
  2640.  
  2641.         /*
  2642.          * We can do it without term_windgoto()!
  2643.          */
  2644.         if (cost < goto_cost)
  2645.         {
  2646.         if (plan == PLAN_LE)
  2647.         {
  2648.             if (noinvcurs)
  2649.             screen_stop_highlight();
  2650.             while (screen_cur_col > col)
  2651.             {
  2652.             out_str(bs);
  2653.             --screen_cur_col;
  2654.             }
  2655.         }
  2656.         else if (plan == PLAN_CR)
  2657.         {
  2658.             if (noinvcurs)
  2659.             screen_stop_highlight();
  2660.             out_char('\r');
  2661.             screen_cur_col = 0;
  2662.         }
  2663.         else if (plan == PLAN_NL)
  2664.         {
  2665.             if (noinvcurs)
  2666.             screen_stop_highlight();
  2667.             while (screen_cur_row < row)
  2668.             {
  2669.             out_char('\n');
  2670.             ++screen_cur_row;
  2671.             }
  2672.             screen_cur_col = 0;
  2673.         }
  2674.  
  2675.         i = col - screen_cur_col;
  2676.         if (i > 0)
  2677.         {
  2678.             /*
  2679.              * Use cursor-right if it's one character only.  Avoids
  2680.              * removing a line of pixels from the last bold char, when
  2681.              * using the bold trick in the GUI.
  2682.              */
  2683.             if (T_ND[0] != NUL && T_ND[1] == NUL)
  2684.             {
  2685.             while (i--)
  2686.                 out_char(*T_ND);
  2687.             }
  2688.             else
  2689.             {
  2690.             p = LinePointers[row] + screen_cur_col;
  2691.             while (i--)
  2692.             {
  2693.                 if (*(p + Columns) != screen_attr)
  2694.                 screen_stop_highlight();
  2695.                 out_char(*p++);
  2696.             }
  2697.             }
  2698.         }
  2699.         }
  2700.     }
  2701.     else
  2702.         cost = 999;
  2703.  
  2704.     if (cost >= goto_cost)
  2705.     {
  2706.         if (noinvcurs)
  2707.         screen_stop_highlight();
  2708.         if (row == screen_cur_row && (col > screen_cur_col) &&
  2709.                                 *T_CRI != NUL)
  2710.         term_cursor_right(col - screen_cur_col);
  2711.         else
  2712.         term_windgoto(row, col);
  2713.     }
  2714.     screen_cur_row = row;
  2715.     screen_cur_col = col;
  2716.     }
  2717. }
  2718.  
  2719. /*
  2720.  * Set cursor to current position.
  2721.  */
  2722.     void
  2723. setcursor()
  2724. {
  2725.     if (redrawing())
  2726.     {
  2727.     validate_cursor();
  2728.     windgoto(curwin->w_winpos + curwin->w_wrow,
  2729. #ifdef RIGHTLEFT
  2730.         curwin->w_p_rl ? ((int)Columns - 1 - curwin->w_wcol) :
  2731. #endif
  2732.                                 curwin->w_wcol);
  2733.     }
  2734. }
  2735.  
  2736. /*
  2737.  * Recompute topline to put the cursor at the top of the window.
  2738.  * Scroll at least "min_scroll" lines.
  2739.  * If "always" is TRUE, always set topline (for "zt").
  2740.  */
  2741.     void
  2742. scroll_cursor_top(min_scroll, always)
  2743.     int        min_scroll;
  2744.     int        always;
  2745. {
  2746.     int        scrolled = 0;
  2747.     int        extra = 0;
  2748.     int        used;
  2749.     int        i;
  2750.     int        sline;    /* screen line for cursor */
  2751.     int        old_topline = curwin->w_topline;
  2752.  
  2753.     /*
  2754.      * Decrease topline until:
  2755.      * - it has become 1
  2756.      * - (part of) the cursor line is moved off the screen or
  2757.      * - moved at least 'scrolljump' lines and
  2758.      * - at least 'scrolloff' lines above and below the cursor
  2759.      */
  2760.     validate_cheight();
  2761.     used = curwin->w_cline_height;
  2762.     for (sline = 1; sline < curwin->w_cursor.lnum; ++sline)
  2763.     {
  2764.     i = plines(curwin->w_cursor.lnum - sline);
  2765.     used += i;
  2766.     extra += i;
  2767.     if (extra <= p_so &&
  2768.            curwin->w_cursor.lnum + sline < curbuf->b_ml.ml_line_count)
  2769.         used += plines(curwin->w_cursor.lnum + sline);
  2770.     if (used > curwin->w_height)
  2771.         break;
  2772.     if (curwin->w_cursor.lnum - sline < curwin->w_topline)
  2773.         scrolled += i;
  2774.  
  2775.     /*
  2776.      * If scrolling is needed, scroll at least 'sj' lines.
  2777.      */
  2778.     if ((curwin->w_cursor.lnum - (sline - 1) >= curwin->w_topline ||
  2779.                       scrolled >= min_scroll) && extra > p_so)
  2780.         break;
  2781.     }
  2782.  
  2783.     /*
  2784.      * If we don't have enough space, put cursor in the middle.
  2785.      * This makes sure we get the same position when using "k" and "j"
  2786.      * in a small window.
  2787.      */
  2788.     if (used > curwin->w_height)
  2789.     scroll_cursor_halfway(FALSE);
  2790.     else
  2791.     {
  2792.     /*
  2793.      * If "always" is FALSE, only adjust topline to a lower value, higher
  2794.      * value may happen with wrapping lines
  2795.      */
  2796.     if (curwin->w_cursor.lnum - (sline - 1) < curwin->w_topline || always)
  2797.         curwin->w_topline = curwin->w_cursor.lnum - (sline - 1);
  2798.     if (curwin->w_topline > curwin->w_cursor.lnum)
  2799.         curwin->w_topline = curwin->w_cursor.lnum;
  2800.     if (curwin->w_topline != old_topline)
  2801.         curwin->w_valid &=
  2802.               ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  2803.     }
  2804. }
  2805.  
  2806. /*
  2807.  * Recompute topline to put the cursor at the bottom of the window.
  2808.  * Scroll at least "min_scroll" lines.
  2809.  * If "set_topbot" is TRUE, set topline and botline first (for "zb").
  2810.  * This is messy stuff!!!
  2811.  */
  2812.     void
  2813. scroll_cursor_bot(min_scroll, set_topbot)
  2814.     int        min_scroll;
  2815.     int        set_topbot;
  2816. {
  2817.     int        used;
  2818.     int        scrolled = 0;
  2819.     int        extra = 0;
  2820.     int        sline;        /* screen line for cursor from bottom */
  2821.     int        i;
  2822.     linenr_t    lnum;
  2823.     linenr_t    line_count;
  2824.     linenr_t    old_topline = curwin->w_topline;
  2825.     linenr_t    old_botline = curwin->w_botline;
  2826.     linenr_t    old_valid = curwin->w_valid;
  2827.     int        old_empty_rows = curwin->w_empty_rows;
  2828.     linenr_t    cln;            /* Cursor Line Number */
  2829.  
  2830.     cln = curwin->w_cursor.lnum;
  2831.     if (set_topbot)
  2832.     {
  2833.     used = 0;
  2834.     curwin->w_botline = cln + 1;
  2835.     for (curwin->w_topline = curwin->w_botline;
  2836.         curwin->w_topline != 1;
  2837.         --curwin->w_topline)
  2838.     {
  2839.         i = plines(curwin->w_topline - 1);
  2840.         if (used + i > curwin->w_height)
  2841.         break;
  2842.         used += i;
  2843.     }
  2844.     curwin->w_empty_rows = curwin->w_height - used;
  2845.     curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  2846.     if (curwin->w_topline != old_topline)
  2847.         curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
  2848.     }
  2849.     else
  2850.     validate_botline();
  2851.  
  2852.     validate_cheight();
  2853.     used = curwin->w_cline_height;
  2854.  
  2855.     if (cln >= curwin->w_botline)
  2856.     {
  2857.     scrolled = used;
  2858.     if (cln == curwin->w_botline)
  2859.         scrolled -= curwin->w_empty_rows;
  2860.     }
  2861.  
  2862.     /*
  2863.      * Stop counting lines to scroll when
  2864.      * - hitting start of the file
  2865.      * - scrolled nothing or at least 'sj' lines
  2866.      * - at least 'so' lines below the cursor
  2867.      * - lines between botline and cursor have been counted
  2868.      */
  2869.     for (sline = 1; sline < cln; ++sline)
  2870.     {
  2871.     if ((((scrolled <= 0 || scrolled >= min_scroll) && extra >= p_so) ||
  2872.         cln + sline > curbuf->b_ml.ml_line_count) &&
  2873.         cln - sline < curwin->w_botline)
  2874.         break;
  2875.     i = plines(cln - sline);
  2876.     used += i;
  2877.     if (used > curwin->w_height)
  2878.         break;
  2879.     if (cln - sline >= curwin->w_botline)
  2880.     {
  2881.         scrolled += i;
  2882.         if (cln - sline == curwin->w_botline)
  2883.         scrolled -= curwin->w_empty_rows;
  2884.     }
  2885.     if (cln + sline <= curbuf->b_ml.ml_line_count)
  2886.     {
  2887.         i = plines(cln + sline);
  2888.         used += i;
  2889.         if (used > curwin->w_height)
  2890.         break;
  2891.         if (extra < p_so || scrolled < min_scroll)
  2892.         {
  2893.         extra += i;
  2894.         if (cln + sline >= curwin->w_botline)
  2895.         {
  2896.             scrolled += i;
  2897.             if (cln + sline == curwin->w_botline)
  2898.             scrolled -= curwin->w_empty_rows;
  2899.         }
  2900.         }
  2901.     }
  2902.     }
  2903.     /* curwin->w_empty_rows is larger, no need to scroll */
  2904.     if (scrolled <= 0)
  2905.     line_count = 0;
  2906.     /* more than a screenfull, don't scroll but redraw */
  2907.     else if (used > curwin->w_height)
  2908.     line_count = used;
  2909.     /* scroll minimal number of lines */
  2910.     else
  2911.     {
  2912.     for (i = 0, lnum = curwin->w_topline;
  2913.         i < scrolled && lnum < curwin->w_botline; ++lnum)
  2914.         i += plines(lnum);
  2915.     if (i >= scrolled)    /* it's possible to scroll */
  2916.         line_count = lnum - curwin->w_topline;
  2917.     else            /* below curwin->w_botline, don't scroll */
  2918.         line_count = 9999;
  2919.     }
  2920.  
  2921.     /*
  2922.      * Scroll up if the cursor is off the bottom of the screen a bit.
  2923.      * Otherwise put it at 1/2 of the screen.
  2924.      */
  2925.     if (line_count >= curwin->w_height && line_count > min_scroll)
  2926.     scroll_cursor_halfway(FALSE);
  2927.     else
  2928.     scrollup(line_count);
  2929.  
  2930.     /*
  2931.      * If topline didn't change we need to restore w_botline and w_empty_rows
  2932.      * (we changed them).
  2933.      * If topline did change, update_screen() will set botline.
  2934.      */
  2935.     if (curwin->w_topline == old_topline && set_topbot)
  2936.     {
  2937.     curwin->w_botline = old_botline;
  2938.     curwin->w_empty_rows = old_empty_rows;
  2939.     curwin->w_valid = old_valid;
  2940.     }
  2941. }
  2942.  
  2943. /*
  2944.  * Recompute topline to put the cursor halfway the window
  2945.  * If "atend" is TRUE, also put it halfway at the end of the file.
  2946.  */
  2947.     void
  2948. scroll_cursor_halfway(atend)
  2949.     int        atend;
  2950. {
  2951.     int        above = 0;
  2952.     linenr_t    topline;
  2953.     int        below = 0;
  2954.     linenr_t    botline;
  2955.     int        used;
  2956.     int        i;
  2957.     linenr_t    cln;            /* Cursor Line Number */
  2958.  
  2959.     topline = botline = cln = curwin->w_cursor.lnum;
  2960.     used = plines(cln);
  2961.     while (topline > 1)
  2962.     {
  2963.     if (below <= above)        /* add a line below the cursor */
  2964.     {
  2965.         if (botline + 1 <= curbuf->b_ml.ml_line_count)
  2966.         {
  2967.         i = plines(botline + 1);
  2968.         used += i;
  2969.         if (used > curwin->w_height)
  2970.             break;
  2971.         below += i;
  2972.         ++botline;
  2973.         }
  2974.         else
  2975.         {
  2976.         ++below;        /* count a "~" line */
  2977.         if (atend)
  2978.             ++used;
  2979.         }
  2980.     }
  2981.  
  2982.     if (below > above)        /* add a line above the cursor */
  2983.     {
  2984.         i = plines(topline - 1);
  2985.         used += i;
  2986.         if (used > curwin->w_height)
  2987.         break;
  2988.         above += i;
  2989.         --topline;
  2990.     }
  2991.     }
  2992.     curwin->w_topline = topline;
  2993.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  2994. }
  2995.  
  2996. /*
  2997.  * Correct the cursor position so that it is in a part of the screen at least
  2998.  * 'so' lines from the top and bottom, if possible.
  2999.  * If not possible, put it at the same position as scroll_cursor_halfway().
  3000.  * When called topline must be valid!
  3001.  */
  3002.     void
  3003. cursor_correct()
  3004. {
  3005.     int        above = 0;        /* screen lines above topline */
  3006.     linenr_t    topline;
  3007.     int        below = 0;        /* screen lines below botline */
  3008.     linenr_t    botline;
  3009.     int        above_wanted, below_wanted;
  3010.     linenr_t    cln;            /* Cursor Line Number */
  3011.     int        max_off;
  3012.  
  3013.     /*
  3014.      * How many lines we would like to have above/below the cursor depends on
  3015.      * whether the first/last line of the file is on screen.
  3016.      */
  3017.     above_wanted = p_so;
  3018.     below_wanted = p_so;
  3019.     if (curwin->w_topline == 1)
  3020.     {
  3021.     above_wanted = 0;
  3022.     max_off = curwin->w_height / 2;
  3023.     if (below_wanted > max_off)
  3024.         below_wanted = max_off;
  3025.     }
  3026.     validate_botline();
  3027.     if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1)
  3028.     {
  3029.     below_wanted = 0;
  3030.     max_off = (curwin->w_height - 1) / 2;
  3031.     if (above_wanted > max_off)
  3032.         above_wanted = max_off;
  3033.     }
  3034.  
  3035.     /*
  3036.      * If there are sufficient file-lines above and below the cursor, we can
  3037.      * return now.
  3038.      */
  3039.     cln = curwin->w_cursor.lnum;
  3040.     if (cln >= curwin->w_topline + above_wanted &&
  3041.                       cln < curwin->w_botline - below_wanted)
  3042.     return;
  3043.  
  3044.     /*
  3045.      * Narrow down the area where the cursor can be put by taking lines from
  3046.      * the top and the bottom until:
  3047.      * - the desired context lines are found
  3048.      * - the lines from the top is past the lines from the bottom
  3049.      */
  3050.     topline = curwin->w_topline;
  3051.     botline = curwin->w_botline - 1;
  3052.     while ((above < above_wanted || below < below_wanted) && topline < botline)
  3053.     {
  3054.     if (below < below_wanted && (below <= above || above >= above_wanted))
  3055.     {
  3056.         below += plines(botline);
  3057.         --botline;
  3058.     }
  3059.     if (above < above_wanted && (above < below || below >= below_wanted))
  3060.     {
  3061.         above += plines(topline);
  3062.         ++topline;
  3063.     }
  3064.     }
  3065.     if (topline == botline || botline == 0)
  3066.     curwin->w_cursor.lnum = topline;
  3067.     else if (topline > botline)
  3068.     curwin->w_cursor.lnum = botline;
  3069.     else
  3070.     {
  3071.     if (cln < topline && curwin->w_topline > 1)
  3072.     {
  3073.         curwin->w_cursor.lnum = topline;
  3074.         curwin->w_valid &=
  3075.                 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
  3076.     }
  3077.     if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
  3078.     {
  3079.         curwin->w_cursor.lnum = botline;
  3080.         curwin->w_valid &=
  3081.                 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
  3082.     }
  3083.     }
  3084. }
  3085.  
  3086.  
  3087. /*
  3088.  * Check if the cursor has moved.  Set the w_valid flag accordingly.
  3089.  */
  3090.     static void
  3091. check_cursor_moved(wp)
  3092.     WIN        *wp;
  3093. {
  3094.     if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum)
  3095.     {
  3096.     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
  3097.                            |VALID_CHEIGHT|VALID_CROW);
  3098.     wp->w_valid_cursor = wp->w_cursor;
  3099.     wp->w_valid_leftcol = wp->w_leftcol;
  3100.     }
  3101.     else if (wp->w_cursor.col != wp->w_valid_cursor.col
  3102.          || wp->w_leftcol != wp->w_valid_leftcol)
  3103.     {
  3104.     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
  3105.     wp->w_valid_cursor.col = wp->w_cursor.col;
  3106.     wp->w_valid_leftcol = wp->w_leftcol;
  3107.     }
  3108. }
  3109.  
  3110. /*
  3111.  * Call this function when the length of the cursor line (in screen
  3112.  * characters) has changed, and the change is before the cursor.
  3113.  * Need to take care of w_botline separately!
  3114.  */
  3115.     void
  3116. changed_cline_bef_curs()
  3117. {
  3118.     curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CHEIGHT);
  3119. }
  3120.  
  3121. /*
  3122.  * Call this function when the length of the cursor line (in screen
  3123.  * characters) has changed, and the position of the cursor doesn't change.
  3124.  * Need to take care of w_botline separately!
  3125.  */
  3126.     void
  3127. changed_cline_aft_curs()
  3128. {
  3129.     curwin->w_valid &= ~VALID_CHEIGHT;
  3130. }
  3131.  
  3132. /*
  3133.  * Call this function when the length of a line (in screen characters) above
  3134.  * the cursor have changed.
  3135.  * Need to take care of w_botline separately!
  3136.  */
  3137.     void
  3138. changed_line_abv_curs()
  3139. {
  3140.     curwin->w_valid &=
  3141.           ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW|VALID_CHEIGHT);
  3142. }
  3143.  
  3144. /*
  3145.  * Set wp->w_topline to a certain number.
  3146.  */
  3147.     void
  3148. set_topline(wp, lnum)
  3149.     WIN            *wp;
  3150.     linenr_t        lnum;
  3151. {
  3152.     /* Approximate the value of w_botline */
  3153.     wp->w_botline += lnum - wp->w_topline;
  3154.     wp->w_topline = lnum;
  3155.     wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  3156. }
  3157.  
  3158. /*
  3159.  * Make sure the value of curwin->w_botline is valid.
  3160.  */
  3161.     void
  3162. validate_botline()
  3163. {
  3164.     if (!(curwin->w_valid & VALID_BOTLINE))
  3165.     comp_botline();
  3166. }
  3167.  
  3168. /*
  3169.  * Mark curwin->w_botline as invalid (because of some change in the buffer).
  3170.  */
  3171.     void
  3172. invalidate_botline()
  3173. {
  3174.     curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
  3175. }
  3176.  
  3177.     void
  3178. invalidate_botline_win(wp)
  3179.     WIN        *wp;
  3180. {
  3181.     wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
  3182. }
  3183.  
  3184. /*
  3185.  * Mark curwin->w_botline as approximated (because of some small change in the
  3186.  * buffer).
  3187.  */
  3188.     void
  3189. approximate_botline()
  3190. {
  3191.     curwin->w_valid &= ~VALID_BOTLINE;
  3192. }
  3193.  
  3194. /*
  3195.  * Return TRUE if curwin->w_botline is valid.
  3196.  */
  3197.     int
  3198. botline_valid()
  3199. {
  3200.     return (curwin->w_valid & VALID_BOTLINE);
  3201. }
  3202.  
  3203. /*
  3204.  * Return TRUE if curwin->w_botline is valid or approximated.
  3205.  */
  3206.     int
  3207. botline_approximated()
  3208. {
  3209.     return (curwin->w_valid & VALID_BOTLINE_AP);
  3210. }
  3211.  
  3212. /*
  3213.  * Return TRUE if curwin->w_wrow and curwin->w_wcol are valid.
  3214.  */
  3215.     int
  3216. cursor_valid()
  3217. {
  3218.     check_cursor_moved(curwin);
  3219.     return ((curwin->w_valid & (VALID_WROW|VALID_WCOL)) ==
  3220.                               (VALID_WROW|VALID_WCOL));
  3221. }
  3222.  
  3223. /*
  3224.  * Validate cursor position.  Makes sure w_wrow and w_wcol are valid.
  3225.  * w_topline must be valid, you may need to call update_topline() first!
  3226.  */
  3227.     void
  3228. validate_cursor()
  3229. {
  3230.     check_cursor_moved(curwin);
  3231.     if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW))
  3232.     curs_columns(TRUE);
  3233. }
  3234.  
  3235. /*
  3236.  * validate w_cline_row.
  3237.  */
  3238.     void
  3239. validate_cline_row()
  3240. {
  3241.     /*
  3242.      * First make sure that w_topline is valid (after moving the cursor).
  3243.      */
  3244.     update_topline();
  3245.     check_cursor_moved(curwin);
  3246.     if (!(curwin->w_valid & VALID_CROW))
  3247.     curs_rows(FALSE);
  3248. }
  3249.  
  3250. /*
  3251.  * Check if w_cline_row and w_cline_height are valid, or can be made valid.
  3252.  * Can be called when topline and botline have not been updated.
  3253.  * Used to decide to redraw or keep the window update.
  3254.  *
  3255.  * Return OK if w_cline_row is valid.
  3256.  */
  3257.     int
  3258. may_validate_crow()
  3259. {
  3260.     if (curwin->w_cursor.lnum < curwin->w_topline ||
  3261.         curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count ||
  3262.         !(curwin->w_valid & (VALID_BOTLINE|VALID_BOTLINE_AP)) ||
  3263.         curwin->w_cursor.lnum >= curwin->w_botline)
  3264.     return FAIL;
  3265.  
  3266.     check_cursor_moved(curwin);
  3267.     if ((curwin->w_valid & (VALID_CROW|VALID_CHEIGHT)) !=
  3268.               (VALID_CROW|VALID_CHEIGHT))
  3269.     curs_rows(TRUE);
  3270.     return OK;
  3271. }
  3272.  
  3273. /*
  3274.  * Compute curwin->w_cline_row and curwin->w_cline_height.
  3275.  * Must only be called when w_topine is valid!
  3276.  *
  3277.  * Returns OK when cursor is in the window, FAIL when it isn't.
  3278.  */
  3279.     static void
  3280. curs_rows(do_botline)
  3281.     int        do_botline;        /* also compute w_botline */
  3282. {
  3283.     linenr_t    lnum;
  3284.     int        i;
  3285.     int        lsize_invalid;
  3286.  
  3287.     /* Check if curwin->w_lsize[] is invalid */
  3288.     lsize_invalid = (!redrawing() || curwin->w_lsize_valid == 0 ||
  3289.                 curwin->w_lsize_lnum[0] != curwin->w_topline);
  3290.     i = 0;
  3291.     curwin->w_cline_row = 0;
  3292.     for (lnum = curwin->w_topline; lnum < curwin->w_cursor.lnum; ++lnum)
  3293.     if (lsize_invalid)
  3294.         curwin->w_cline_row += plines(lnum);
  3295.     else
  3296.         curwin->w_cline_row += curwin->w_lsize[i++];
  3297.  
  3298.     check_cursor_moved(curwin);
  3299.     if (!(curwin->w_valid & VALID_CHEIGHT))
  3300.     {
  3301.     if (lsize_invalid)
  3302.         curwin->w_cline_height = plines(lnum);
  3303.     /* Check for a line that is too long to fit on the last screen line. */
  3304.     else if (i > curwin->w_lsize_valid)
  3305.         curwin->w_cline_height = 0;
  3306.     else
  3307.         curwin->w_cline_height = curwin->w_lsize[i];
  3308.     }
  3309.  
  3310.     curwin->w_valid |= VALID_CROW|VALID_CHEIGHT;
  3311.  
  3312.     /* validate botline too, if update_screen doesn't do it */
  3313.     if (do_botline && lsize_invalid)
  3314.     validate_botline();
  3315. }
  3316.  
  3317. /*
  3318.  * Validate curwin->w_virtcol only.
  3319.  */
  3320.     void
  3321. validate_virtcol()
  3322. {
  3323.     validate_virtcol_win(curwin);
  3324. }
  3325.  
  3326. /*
  3327.  * Validate wp->w_virtcol only.
  3328.  */
  3329.     static void
  3330. validate_virtcol_win(wp)
  3331.     WIN        *wp;
  3332. {
  3333.     check_cursor_moved(wp);
  3334.     if (!(wp->w_valid & VALID_VIRTCOL))
  3335.     {
  3336.     getvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL);
  3337.     wp->w_valid |= VALID_VIRTCOL;
  3338.     }
  3339. }
  3340.  
  3341. /*
  3342.  * Validate curwin->w_cline_height only.
  3343.  */
  3344.     void
  3345. validate_cheight()
  3346. {
  3347.     check_cursor_moved(curwin);
  3348.     if (!(curwin->w_valid & VALID_CHEIGHT))
  3349.     {
  3350.     curwin->w_cline_height = plines(curwin->w_cursor.lnum);
  3351.     curwin->w_valid |= VALID_CHEIGHT;
  3352.     }
  3353. }
  3354.  
  3355. /*
  3356.  * validate w_wcol and w_virtcol only.    Only for when 'wrap' on!
  3357.  */
  3358.     void
  3359. validate_cursor_col()
  3360. {
  3361.     validate_virtcol();
  3362.     if (!(curwin->w_valid & VALID_WCOL))
  3363.     {
  3364.     curwin->w_wcol = curwin->w_virtcol;
  3365.     if (curwin->w_p_nu)
  3366.         curwin->w_wcol += 8;
  3367.  
  3368.     /* long line wrapping, adjust curwin->w_wrow */
  3369.     if (curwin->w_p_wrap && curwin->w_wcol >= Columns)
  3370.         curwin->w_wcol = curwin->w_wcol % Columns;
  3371.  
  3372.     curwin->w_valid |= VALID_WCOL;
  3373.     }
  3374. }
  3375.  
  3376. /*
  3377.  * compute curwin->w_wcol and curwin->w_virtcol.
  3378.  * Also updates curwin->w_wrow and curwin->w_cline_row.
  3379.  */
  3380.     void
  3381. curs_columns(scroll)
  3382.     int scroll;        /* when TRUE, may scroll horizontally */
  3383. {
  3384.     int        diff;
  3385.     int        extra;
  3386.     int        new_leftcol;
  3387.     colnr_t startcol;
  3388.     colnr_t endcol;
  3389.  
  3390.     /*
  3391.      * First make sure that w_topline is valid (after moving the cursor).
  3392.      */
  3393.     update_topline();
  3394.  
  3395.     /*
  3396.      * Next make sure that w_cline_row is valid.
  3397.      */
  3398.     if (!(curwin->w_valid & VALID_CROW))
  3399.     curs_rows(FALSE);
  3400.  
  3401.     /*
  3402.      * Compute the number of virtual columns.
  3403.      */
  3404.     getvcol(curwin, &curwin->w_cursor,
  3405.                 &startcol, &(curwin->w_virtcol), &endcol);
  3406.  
  3407.     /* remove '$' from change command when cursor moves onto it */
  3408.     if (startcol > dollar_vcol)
  3409.     dollar_vcol = 0;
  3410.  
  3411.     curwin->w_wcol = curwin->w_virtcol;
  3412.     if (curwin->w_p_nu)
  3413.     {
  3414.     curwin->w_wcol += 8;
  3415.     endcol += 8;
  3416.     }
  3417.  
  3418.     /*
  3419.      * Now compute w_wrow, counting screen lines from w_cline_row.
  3420.      */
  3421.     curwin->w_wrow = curwin->w_cline_row;
  3422.  
  3423.     if (curwin->w_p_wrap)    /* long line wrapping, adjust curwin->w_wrow */
  3424.     {
  3425.     while (curwin->w_wcol >= Columns)
  3426.     {
  3427.         curwin->w_wcol -= Columns;
  3428.         curwin->w_wrow++;
  3429.     }
  3430.     }
  3431.     else if (scroll)    /* no line wrapping, compute curwin->w_leftcol if
  3432.              * scrolling is on.  If scrolling is off,
  3433.              * curwin->w_leftcol is assumed to be 0 */
  3434.     {
  3435.             /* If Cursor is left of the screen, scroll rightwards */
  3436.             /* If Cursor is right of the screen, scroll leftwards */
  3437.     if ((extra = (int)startcol - (int)curwin->w_leftcol) < 0 ||
  3438.          (extra = (int)endcol - (int)(curwin->w_leftcol + Columns) + 1) > 0)
  3439.     {
  3440.         if (extra < 0)
  3441.         diff = -extra;
  3442.         else
  3443.         diff = extra;
  3444.  
  3445.         /* far off, put cursor in middle of window */
  3446.         if (p_ss == 0 || diff >= Columns / 2)
  3447.         new_leftcol = curwin->w_wcol - Columns / 2;
  3448.         else
  3449.         {
  3450.         if (diff < p_ss)
  3451.             diff = p_ss;
  3452.         if (extra < 0)
  3453.             new_leftcol = curwin->w_leftcol - diff;
  3454.         else
  3455.             new_leftcol = curwin->w_leftcol + diff;
  3456.         }
  3457.         if (new_leftcol < 0)
  3458.         curwin->w_leftcol = 0;
  3459.         else
  3460.         curwin->w_leftcol = new_leftcol;
  3461.             /* screen has to be redrawn with new curwin->w_leftcol */
  3462.         redraw_later(NOT_VALID);
  3463.     }
  3464.     curwin->w_wcol -= curwin->w_leftcol;
  3465.     }
  3466.     else if (curwin->w_wcol > (int)curwin->w_leftcol)
  3467.     curwin->w_wcol -= curwin->w_leftcol;
  3468.     else
  3469.     curwin->w_wcol = 0;
  3470.  
  3471.     /* Cursor past end of screen */
  3472.     /* happens with line that does not fit on screen */
  3473.     if (curwin->w_wrow > curwin->w_height - 1)
  3474.     curwin->w_wrow = curwin->w_height - 1;
  3475.  
  3476.     curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
  3477. }
  3478.  
  3479. /*
  3480.  * Scroll up 'line_count' lines.
  3481.  */
  3482.     void
  3483. scrolldown(line_count)
  3484.     long    line_count;
  3485. {
  3486.     long    done = 0;        /* total # of physical lines done */
  3487.     int        wrow;
  3488.     int        moved = FALSE;
  3489.  
  3490.     validate_cursor();        /* w_wrow needs to be valid */
  3491.     while (line_count--)
  3492.     {
  3493.     if (curwin->w_topline == 1)
  3494.         break;
  3495.     done += plines(--curwin->w_topline);
  3496.     --curwin->w_botline;        /* approximate w_botline */
  3497.     curwin->w_valid &= ~VALID_BOTLINE;
  3498.     }
  3499.     curwin->w_wrow += done;        /* keep w_wrow updated */
  3500.     curwin->w_cline_row += done;    /* keep w_cline_row updated */
  3501.  
  3502.     /*
  3503.      * Compute the row number of the last row of the cursor line
  3504.      * and move it onto the screen.
  3505.      */
  3506.     wrow = curwin->w_wrow;
  3507.     if (curwin->w_p_wrap)
  3508.     {
  3509.     validate_virtcol();
  3510.     validate_cheight();
  3511.     wrow += curwin->w_cline_height - 1 - curwin->w_virtcol / Columns;
  3512.     }
  3513.     while (wrow >= curwin->w_height && curwin->w_cursor.lnum > 1)
  3514.     {
  3515.     wrow -= plines(curwin->w_cursor.lnum--);
  3516.     curwin->w_valid &=
  3517.           ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
  3518.     moved = TRUE;
  3519.     }
  3520.     if (moved)
  3521.     coladvance(curwin->w_curswant);
  3522. }
  3523.  
  3524.     void
  3525. scrollup(line_count)
  3526.     long    line_count;
  3527. {
  3528.     curwin->w_topline += line_count;
  3529.     curwin->w_botline += line_count;        /* approximate w_botline */
  3530.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  3531.     if (curwin->w_topline > curbuf->b_ml.ml_line_count)
  3532.     curwin->w_topline = curbuf->b_ml.ml_line_count;
  3533.     if (curwin->w_cursor.lnum < curwin->w_topline)
  3534.     {
  3535.     curwin->w_cursor.lnum = curwin->w_topline;
  3536.     curwin->w_valid &=
  3537.           ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
  3538.     coladvance(curwin->w_curswant);
  3539.     }
  3540. }
  3541.  
  3542. /*
  3543.  * Scroll the screen one line down, but don't do it if it would move the
  3544.  * cursor off the screen.
  3545.  */
  3546.     void
  3547. scrolldown_clamp()
  3548. {
  3549.     int        end_row;
  3550.  
  3551.     if (curwin->w_topline == 1)
  3552.     return;
  3553.  
  3554.     validate_cursor();        /* w_wrow needs to be valid */
  3555.  
  3556.     /*
  3557.      * Compute the row number of the last row of the cursor line
  3558.      * and make sure it doesn't go off the screen. Make sure the cursor
  3559.      * doesn't go past 'scrolloff' lines from the screen end.
  3560.      */
  3561.     end_row = curwin->w_wrow + plines(curwin->w_topline - 1);
  3562.     if (curwin->w_p_wrap)
  3563.     {
  3564.     validate_cheight();
  3565.     validate_virtcol();
  3566.     end_row += curwin->w_cline_height - 1 - curwin->w_virtcol / Columns;
  3567.     }
  3568.     if (end_row < curwin->w_height - p_so)
  3569.     {
  3570.     --curwin->w_topline;
  3571.     --curwin->w_botline;        /* approximate w_botline */
  3572.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  3573.     }
  3574. }
  3575.  
  3576. /*
  3577.  * Scroll the screen one line up, but don't do it if it would move the cursor
  3578.  * off the screen.
  3579.  */
  3580.     void
  3581. scrollup_clamp()
  3582. {
  3583.     int        start_row;
  3584.  
  3585.     if (curwin->w_topline == curbuf->b_ml.ml_line_count)
  3586.     return;
  3587.  
  3588.     validate_cursor();        /* w_wrow needs to be valid */
  3589.  
  3590.     /*
  3591.      * Compute the row number of the first row of the cursor line
  3592.      * and make sure it doesn't go off the screen. Make sure the cursor
  3593.      * doesn't go before 'scrolloff' lines from the screen start.
  3594.      */
  3595.     start_row = curwin->w_wrow - plines(curwin->w_topline);
  3596.     if (curwin->w_p_wrap)
  3597.     {
  3598.     validate_virtcol();
  3599.     start_row -= curwin->w_virtcol / Columns;
  3600.     }
  3601.     if (start_row >= p_so)
  3602.     {
  3603.     ++curwin->w_topline;
  3604.     ++curwin->w_botline;        /* approximate w_botline */
  3605.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  3606.     }
  3607. }
  3608.  
  3609. /*
  3610.  * insert 'line_count' lines at 'row' in window 'wp'
  3611.  * if 'invalid' is TRUE the wp->w_lsize_lnum[] is invalidated.
  3612.  * if 'mayclear' is TRUE the screen will be cleared if it is faster than
  3613.  * scrolling.
  3614.  * Returns FAIL if the lines are not inserted, OK for success.
  3615.  */
  3616.     int
  3617. win_ins_lines(wp, row, line_count, invalid, mayclear)
  3618.     WIN        *wp;
  3619.     int        row;
  3620.     int        line_count;
  3621.     int        invalid;
  3622.     int        mayclear;
  3623. {
  3624.     int        did_delete;
  3625.     int        nextrow;
  3626.     int        lastrow;
  3627.     int        retval;
  3628.  
  3629.     if (invalid)
  3630.     wp->w_lsize_valid = 0;
  3631.  
  3632.     if (!redrawing() || line_count <= 0 || wp->w_height < 5)
  3633.     return FAIL;
  3634.  
  3635.     if (line_count > wp->w_height - row)
  3636.     line_count = wp->w_height - row;
  3637.  
  3638.     if (mayclear && Rows - line_count < 5)  /* only a few lines left: redraw is faster */
  3639.     {
  3640.     screenclear();        /* will set wp->w_lsize_valid to 0 */
  3641.     return FAIL;
  3642.     }
  3643.  
  3644.     /*
  3645.      * Delete all remaining lines
  3646.      */
  3647.     if (row + line_count >= wp->w_height)
  3648.     {
  3649.     screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
  3650.                         0, (int)Columns, ' ', ' ', 0);
  3651.     return OK;
  3652.     }
  3653.  
  3654.     /*
  3655.      * when scrolling, the message on the command line should be cleared,
  3656.      * otherwise it will stay there forever.
  3657.      */
  3658.     clear_cmdline = TRUE;
  3659.  
  3660.     /*
  3661.      * if the terminal can set a scroll region, use that
  3662.      */
  3663.     if (scroll_region)
  3664.     {
  3665.     scroll_region_set(wp, row);
  3666.     retval = screen_ins_lines(wp->w_winpos + row, 0, line_count,
  3667.                               wp->w_height - row);
  3668.     scroll_region_reset();
  3669.     return retval;
  3670.     }
  3671.  
  3672.     if (wp->w_next && p_tf)    /* don't delete/insert on fast terminal */
  3673.     return FAIL;
  3674.  
  3675.     /*
  3676.      * If there is a next window or a status line, we first try to delete the
  3677.      * lines at the bottom to avoid messing what is after the window.
  3678.      * If this fails and there are following windows, don't do anything to avoid
  3679.      * messing up those windows, better just redraw.
  3680.      */
  3681.     did_delete = FALSE;
  3682.     if (wp->w_next || wp->w_status_height)
  3683.     {
  3684.     if (screen_del_lines(0, wp->w_winpos + wp->w_height - line_count,
  3685.                       line_count, (int)Rows, FALSE) == OK)
  3686.         did_delete = TRUE;
  3687.     else if (wp->w_next)
  3688.         return FAIL;
  3689.     }
  3690.     /*
  3691.      * if no lines deleted, blank the lines that will end up below the window
  3692.      */
  3693.     if (!did_delete)
  3694.     {
  3695.     wp->w_redr_status = TRUE;
  3696.     redraw_cmdline = TRUE;
  3697.     nextrow = wp->w_winpos + wp->w_height + wp->w_status_height;
  3698.     lastrow = nextrow + line_count;
  3699.     if (lastrow > Rows)
  3700.         lastrow = Rows;
  3701.     screen_fill(nextrow - line_count, lastrow - line_count,
  3702.                         0, (int)Columns, ' ', ' ', 0);
  3703.     }
  3704.  
  3705.     if (screen_ins_lines(0, wp->w_winpos + row, line_count, (int)Rows) == FAIL)
  3706.     {
  3707.         /* deletion will have messed up other windows */
  3708.     if (did_delete)
  3709.     {
  3710.         wp->w_redr_status = TRUE;
  3711.         win_rest_invalid(wp->w_next);
  3712.     }
  3713.     return FAIL;
  3714.     }
  3715.  
  3716.     return OK;
  3717. }
  3718.  
  3719. /*
  3720.  * delete 'line_count' lines at 'row' in window 'wp'
  3721.  * If 'invalid' is TRUE curwin->w_lsize_lnum[] is invalidated.
  3722.  * If 'mayclear' is TRUE the screen will be cleared if it is faster than
  3723.  * scrolling
  3724.  * Return OK for success, FAIL if the lines are not deleted.
  3725.  */
  3726.     int
  3727. win_del_lines(wp, row, line_count, invalid, mayclear)
  3728.     WIN            *wp;
  3729.     int            row;
  3730.     int            line_count;
  3731.     int            invalid;
  3732.     int            mayclear;
  3733. {
  3734.     int        retval;
  3735.  
  3736.     if (invalid)
  3737.     wp->w_lsize_valid = 0;
  3738.  
  3739.     if (!redrawing() || line_count <= 0)
  3740.     return FAIL;
  3741.  
  3742.     if (line_count > wp->w_height - row)
  3743.     line_count = wp->w_height - row;
  3744.  
  3745.     /* only a few lines left: redraw is faster */
  3746.     if (mayclear && Rows - line_count < 5)
  3747.     {
  3748.     screenclear();        /* will set wp->w_lsize_valid to 0 */
  3749.     return FAIL;
  3750.     }
  3751.  
  3752.     /*
  3753.      * Delete all remaining lines
  3754.      */
  3755.     if (row + line_count >= wp->w_height)
  3756.     {
  3757.     screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
  3758.                         0, (int)Columns, ' ', ' ', 0);
  3759.     return OK;
  3760.     }
  3761.  
  3762.     /*
  3763.      * when scrolling, the message on the command line should be cleared,
  3764.      * otherwise it will stay there forever.
  3765.      */
  3766.     clear_cmdline = TRUE;
  3767.  
  3768.     /*
  3769.      * if the terminal can set a scroll region, use that
  3770.      */
  3771.     if (scroll_region)
  3772.     {
  3773.     scroll_region_set(wp, row);
  3774.     retval = screen_del_lines(wp->w_winpos + row, 0, line_count,
  3775.                            wp->w_height - row, FALSE);
  3776.     scroll_region_reset();
  3777.     return retval;
  3778.     }
  3779.  
  3780.     if (wp->w_next && p_tf)    /* don't delete/insert on fast terminal */
  3781.     return FAIL;
  3782.  
  3783.     if (screen_del_lines(0, wp->w_winpos + row, line_count,
  3784.                             (int)Rows, FALSE) == FAIL)
  3785.     return FAIL;
  3786.  
  3787.     /*
  3788.      * If there are windows or status lines below, try to put them at the
  3789.      * correct place. If we can't do that, they have to be redrawn.
  3790.      */
  3791.     if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
  3792.     {
  3793.     if (screen_ins_lines(0, wp->w_winpos + wp->w_height - line_count,
  3794.                            line_count, (int)Rows) == FAIL)
  3795.     {
  3796.         wp->w_redr_status = TRUE;
  3797.         win_rest_invalid(wp->w_next);
  3798.     }
  3799.     }
  3800.     /*
  3801.      * If this is the last window and there is no status line, redraw the
  3802.      * command line later.
  3803.      */
  3804.     else
  3805.     redraw_cmdline = TRUE;
  3806.     return OK;
  3807. }
  3808.  
  3809. /*
  3810.  * window 'wp' and everything after it is messed up, mark it for redraw
  3811.  */
  3812.     void
  3813. win_rest_invalid(wp)
  3814.     WIN        *wp;
  3815. {
  3816.     while (wp)
  3817.     {
  3818.     wp->w_lsize_valid = 0;
  3819.     wp->w_redr_type = NOT_VALID;
  3820.     wp->w_redr_status = TRUE;
  3821.     wp = wp->w_next;
  3822.     }
  3823.     redraw_cmdline = TRUE;
  3824. }
  3825.  
  3826. /*
  3827.  * The rest of the routines in this file perform screen manipulations. The
  3828.  * given operation is performed physically on the screen. The corresponding
  3829.  * change is also made to the internal screen image. In this way, the editor
  3830.  * anticipates the effect of editing changes on the appearance of the screen.
  3831.  * That way, when we call screenupdate a complete redraw isn't usually
  3832.  * necessary. Another advantage is that we can keep adding code to anticipate
  3833.  * screen changes, and in the meantime, everything still works.
  3834.  */
  3835.  
  3836. /*
  3837.  * types for inserting or deleting lines
  3838.  */
  3839. #define USE_T_CAL   1
  3840. #define USE_T_CDL   2
  3841. #define USE_T_AL    3
  3842. #define USE_T_CE    4
  3843. #define USE_T_DL    5
  3844. #define USE_T_SR    6
  3845. #define USE_NL        7
  3846. #define USE_T_CD    8
  3847.  
  3848. /*
  3849.  * insert lines on the screen and update NextScreen
  3850.  * 'end' is the line after the scrolled part. Normally it is Rows.
  3851.  * When scrolling region used 'off' is the offset from the top for the region.
  3852.  * 'row' and 'end' are relative to the start of the region.
  3853.  *
  3854.  * return FAIL for failure, OK for success.
  3855.  */
  3856.     static int
  3857. screen_ins_lines(off, row, line_count, end)
  3858.     int        off;
  3859.     int        row;
  3860.     int        line_count;
  3861.     int        end;
  3862. {
  3863.     int        i;
  3864.     int        j;
  3865.     char_u    *temp;
  3866.     int        cursor_row;
  3867.     int        type;
  3868.     int        result_empty;
  3869.  
  3870.     /*
  3871.      * FAIL if
  3872.      * - there is no valid screen
  3873.      * - the screen has to be redrawn completely
  3874.      * - the line count is less than one
  3875.      * - the line count is more than 'ttyscroll'
  3876.      */
  3877.     if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll)
  3878.     return FAIL;
  3879.  
  3880.     /*
  3881.      * There are seven ways to insert lines:
  3882.      * 1. Use T_CD (clear to end of display) if it exists and the result of
  3883.      *      the insert is just empty lines
  3884.      * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
  3885.      *      present or line_count > 1. It looks better if we do all the inserts
  3886.      *      at once.
  3887.      * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
  3888.      *      insert is just empty lines and T_CE is not present or line_count >
  3889.      *      1.
  3890.      * 4. Use T_AL (insert line) if it exists.
  3891.      * 5. Use T_CE (erase line) if it exists and the result of the insert is
  3892.      *      just empty lines.
  3893.      * 6. Use T_DL (delete line) if it exists and the result of the insert is
  3894.      *      just empty lines.
  3895.      * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
  3896.      *      the 'da' flag is not set or we have clear line capability.
  3897.      *
  3898.      * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
  3899.      * the scrollbar for the window. It does have insert line, use that if it
  3900.      * exists.
  3901.      */
  3902.     result_empty = (row + line_count >= end);
  3903.     if (*T_CD != NUL && result_empty)
  3904.     type = USE_T_CD;
  3905.     else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
  3906.     type = USE_T_CAL;
  3907.     else if (*T_CDL != NUL && result_empty && (line_count > 1 || *T_CE == NUL))
  3908.     type = USE_T_CDL;
  3909.     else if (*T_AL != NUL)
  3910.     type = USE_T_AL;
  3911.     else if (*T_CE != NUL && result_empty)
  3912.     type = USE_T_CE;
  3913.     else if (*T_DL != NUL && result_empty)
  3914.     type = USE_T_DL;
  3915.     else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || *T_CE))
  3916.     type = USE_T_SR;
  3917.     else
  3918.     return FAIL;
  3919.  
  3920.     /*
  3921.      * For clearing the lines screen_del_lines is used. This will also take
  3922.      * care of t_db if necessary.
  3923.      */
  3924.     if (type == USE_T_CD || type == USE_T_CDL ||
  3925.                      type == USE_T_CE || type == USE_T_DL)
  3926.     return screen_del_lines(off, row, line_count, end, FALSE);
  3927.  
  3928.     /*
  3929.      * If text is retained below the screen, first clear or delete as many
  3930.      * lines at the bottom of the window as are about to be inserted so that
  3931.      * the deleted lines won't later surface during a screen_del_lines.
  3932.      */
  3933.     if (*T_DB)
  3934.     screen_del_lines(off, end - line_count, line_count, end, FALSE);
  3935.  
  3936. #ifdef USE_GUI_BEOS
  3937.     vim_lock_screen();
  3938. #endif
  3939.     if (*T_CCS != NUL)       /* cursor relative to region */
  3940.     cursor_row = row;
  3941.     else
  3942.     cursor_row = row + off;
  3943.  
  3944.     /*
  3945.      * Shift LinePointers line_count down to reflect the inserted lines.
  3946.      * Clear the inserted lines in NextScreen.
  3947.      */
  3948.     row += off;
  3949.     end += off;
  3950.     for (i = 0; i < line_count; ++i)
  3951.     {
  3952.     j = end - 1 - i;
  3953.     temp = LinePointers[j];
  3954.     while ((j -= line_count) >= row)
  3955.         LinePointers[j + line_count] = LinePointers[j];
  3956.     LinePointers[j + line_count] = temp;
  3957.     lineclear(temp);
  3958.     }
  3959. #ifdef USE_GUI_BEOS
  3960.     vim_unlock_screen();
  3961. #endif
  3962.  
  3963.     screen_stop_highlight();
  3964.     windgoto(cursor_row, 0);
  3965.     if (type == USE_T_CAL)
  3966.     {
  3967.     term_append_lines(line_count);
  3968.     screen_start();        /* don't know where cursor is now */
  3969.     }
  3970.     else
  3971.     {
  3972.     for (i = 0; i < line_count; i++)
  3973.     {
  3974.         if (type == USE_T_AL)
  3975.         {
  3976.         if (i && cursor_row != 0)
  3977.             windgoto(cursor_row, 0);
  3978.         out_str(T_AL);
  3979.         }
  3980.         else  /* type == USE_T_SR */
  3981.         out_str(T_SR);
  3982.         screen_start();        /* don't know where cursor is now */
  3983.     }
  3984.     }
  3985.  
  3986.     /*
  3987.      * With scroll-reverse and 'da' flag set we need to clear the lines that
  3988.      * have been scrolled down into the region.
  3989.      */
  3990.     if (type == USE_T_SR && *T_DA)
  3991.     {
  3992.     for (i = 0; i < line_count; ++i)
  3993.     {
  3994.         windgoto(off + i, 0);
  3995.         out_str(T_CE);
  3996.         screen_start();        /* don't know where cursor is now */
  3997.     }
  3998.     }
  3999.  
  4000. #ifdef USE_GUI
  4001.     if (gui.in_use)
  4002.     out_flush();    /* always flush after a scroll */
  4003. #endif
  4004.     return OK;
  4005. }
  4006.  
  4007. /*
  4008.  * delete lines on the screen and update NextScreen
  4009.  * 'end' is the line after the scrolled part. Normally it is Rows.
  4010.  * When scrolling region used 'off' is the offset from the top for the region.
  4011.  * 'row' and 'end' are relative to the start of the region.
  4012.  *
  4013.  * Return OK for success, FAIL if the lines are not deleted.
  4014.  */
  4015.     int
  4016. screen_del_lines(off, row, line_count, end, force)
  4017.     int        off;
  4018.     int        row;
  4019.     int        line_count;
  4020.     int        end;
  4021.     int        force;        /* even when line_count > p_ttyscroll */
  4022. {
  4023.     int        j;
  4024.     int        i;
  4025.     char_u    *temp;
  4026.     int        cursor_row;
  4027.     int        cursor_end;
  4028.     int        result_empty;    /* result is empty until end of region */
  4029.     int        can_delete;    /* deleting line codes can be used */
  4030.     int        type;
  4031.  
  4032.     /*
  4033.      * FAIL if
  4034.      * - there is no valid screen
  4035.      * - the screen has to be redrawn completely
  4036.      * - the line count is less than one
  4037.      * - the line count is more than 'ttyscroll'
  4038.      */
  4039.     if (!screen_valid(TRUE) || line_count <= 0 ||
  4040.                      (!force && line_count > p_ttyscroll))
  4041.     return FAIL;
  4042.  
  4043.     /*
  4044.      * Check if the rest of the current region will become empty.
  4045.      */
  4046.     result_empty = row + line_count >= end;
  4047.  
  4048.     /*
  4049.      * We can delete lines only when 'db' flag not set or when 'ce' option
  4050.      * available.
  4051.      */
  4052.     can_delete = (*T_DB == NUL || *T_CE);
  4053.  
  4054.     /*
  4055.      * There are four ways to delete lines:
  4056.      * 1. Use T_CD if it exists and the result is empty.
  4057.      * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
  4058.      * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
  4059.      *      none of the other ways work.
  4060.      * 4. Use T_CE (erase line) if the result is empty.
  4061.      * 5. Use T_DL (delete line) if it exists.
  4062.      */
  4063.     if (*T_CD != NUL && result_empty)
  4064.     type = USE_T_CD;
  4065. #if defined(__BEOS__) && defined(BEOS_DR8)
  4066.     /*
  4067.      * USE_NL does not seem to work in Terminal of DR8 so we set T_DB="" in
  4068.      * its internal termcap... this works okay for tests which test *T_DB !=
  4069.      * NUL.  It has the disadvantage that the user cannot use any :set t_*
  4070.      * command to get T_DB (back) to empty_option, only :set term=... will do
  4071.      * the trick...
  4072.      * Anyway, this hack will hopefully go away with the next OS release.
  4073.      * (Olaf Seibert)
  4074.      */
  4075.     else if (row == 0 && T_DB == empty_option
  4076.                     && (line_count == 1 || *T_CDL == NUL))
  4077. #else
  4078.     else if (row == 0 && (
  4079. #ifndef AMIGA
  4080.     /* On the Amiga, somehow '\n' on the last line doesn't always scroll
  4081.      * up, so use delete-line command */
  4082.                 line_count == 1 ||
  4083. #endif
  4084.                         *T_CDL == NUL))
  4085. #endif
  4086.     type = USE_NL;
  4087.     else if (*T_CDL != NUL && line_count > 1 && can_delete)
  4088.     type = USE_T_CDL;
  4089.     else if (*T_CE != NUL && result_empty)
  4090.     type = USE_T_CE;
  4091.     else if (*T_DL != NUL && can_delete)
  4092.     type = USE_T_DL;
  4093.     else if (*T_CDL != NUL && can_delete)
  4094.     type = USE_T_CDL;
  4095.     else
  4096.     return FAIL;
  4097.  
  4098. #ifdef USE_GUI_BEOS
  4099.     vim_lock_screen();
  4100. #endif
  4101.     if (*T_CCS != NUL)        /* cursor relative to region */
  4102.     {
  4103.     cursor_row = row;
  4104.     cursor_end = end;
  4105.     }
  4106.     else
  4107.     {
  4108.     cursor_row = row + off;
  4109.     cursor_end = end + off;
  4110.     }
  4111.  
  4112.     /*
  4113.      * Now shift LinePointers line_count up to reflect the deleted lines.
  4114.      * Clear the inserted lines in NextScreen.
  4115.      */
  4116.     row += off;
  4117.     end += off;
  4118.     for (i = 0; i < line_count; ++i)
  4119.     {
  4120.     j = row + i;
  4121.     temp = LinePointers[j];
  4122.     while ((j += line_count) <= end - 1)
  4123.         LinePointers[j - line_count] = LinePointers[j];
  4124.     LinePointers[j - line_count] = temp;
  4125.     lineclear(temp);
  4126.     }
  4127. #ifdef USE_GUI_BEOS
  4128.     vim_unlock_screen();
  4129. #endif
  4130.  
  4131.     /* delete the lines */
  4132.     screen_stop_highlight();
  4133.  
  4134.     if (type == USE_T_CD)
  4135.     {
  4136.     windgoto(cursor_row, 0);
  4137.     out_str(T_CD);
  4138.     screen_start();            /* don't know where cursor is now */
  4139.     }
  4140.     else if (type == USE_T_CDL)
  4141.     {
  4142.     windgoto(cursor_row, 0);
  4143.     term_delete_lines(line_count);
  4144.     screen_start();            /* don't know where cursor is now */
  4145.     }
  4146.     /*
  4147.      * Deleting lines at top of the screen or scroll region: Just scroll
  4148.      * the whole screen (scroll region) up by outputting newlines on the
  4149.      * last line.
  4150.      */
  4151.     else if (type == USE_NL)
  4152.     {
  4153.     windgoto(cursor_end - 1, 0);
  4154.     for (i = line_count; --i >= 0; )
  4155.         out_char('\n');        /* cursor will remain on same line */
  4156.     }
  4157.     else
  4158.     {
  4159.     for (i = line_count; --i >= 0; )
  4160.     {
  4161.         if (type == USE_T_DL)
  4162.         {
  4163.         windgoto(cursor_row, 0);
  4164.         out_str(T_DL);        /* delete a line */
  4165.         }
  4166.         else /* type == USE_T_CE */
  4167.         {
  4168.         windgoto(cursor_row + i, 0);
  4169.         out_str(T_CE);        /* erase a line */
  4170.         }
  4171.         screen_start();        /* don't know where cursor is now */
  4172.     }
  4173.     }
  4174.  
  4175.     /*
  4176.      * If the 'db' flag is set, we need to clear the lines that have been
  4177.      * scrolled up at the bottom of the region.
  4178.      */
  4179.     if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
  4180.     {
  4181.     for (i = line_count; i > 0; --i)
  4182.     {
  4183.         windgoto(cursor_end - i, 0);
  4184.         out_str(T_CE);        /* erase a line */
  4185.         screen_start();        /* don't know where cursor is now */
  4186.     }
  4187.     }
  4188.  
  4189. #ifdef USE_GUI
  4190.     if (gui.in_use)
  4191.     out_flush();    /* always flush after a scroll */
  4192. #endif
  4193.     return OK;
  4194. }
  4195.  
  4196. /*
  4197.  * show the current mode and ruler
  4198.  *
  4199.  * If clear_cmdline is TRUE, clear the rest of the cmdline.
  4200.  * If clear_cmdline is FALSE there may be a message there that needs to be
  4201.  * cleared only if a mode is shown.
  4202.  * Return the length of the message (0 if no message).
  4203.  */
  4204.     int
  4205. showmode()
  4206. {
  4207.     int        need_clear = FALSE;
  4208.     int        length = 0;
  4209.     int        do_mode;
  4210.     int        attr;
  4211. #ifdef INSERT_EXPAND
  4212.     int        sub_attr;
  4213. #endif
  4214.  
  4215.     do_mode = (p_smd && ((State & INSERT) || restart_edit || VIsual_active));
  4216.     if (do_mode || Recording)
  4217.     {
  4218.     /*
  4219.      * Don't show mode right now, when not redrawing or inside a mapping.
  4220.      * Call char_avail() only when we are going to show something, because
  4221.      * it takes a bit of time.
  4222.      */
  4223.     if (!redrawing() || (char_avail() && !KeyTyped))
  4224.     {
  4225.         redraw_cmdline = TRUE;        /* show mode later */
  4226.         return 0;
  4227.     }
  4228.  
  4229.     check_for_delay(FALSE);
  4230.     msg_didout = FALSE;        /* never scroll up */
  4231.     msg_col = 0;
  4232.     gotocmdline(FALSE);
  4233.     attr = highlight_attr[HLF_CM];    /* Highlight mode */
  4234.     if (do_mode)
  4235.     {
  4236.         MSG_PUTS_ATTR("--", attr);
  4237. #ifdef INSERT_EXPAND
  4238.         if (edit_submode != NULL)        /* CTRL-X in Insert mode */
  4239.         {
  4240.         msg_puts_attr(edit_submode, attr);
  4241.         if (edit_submode_extra != NULL)
  4242.         {
  4243.             MSG_PUTS_ATTR(" ", attr);    /* add a space in between */
  4244.             if (edit_submode_highl < HLF_COUNT)
  4245.             sub_attr = highlight_attr[edit_submode_highl];
  4246.             else
  4247.             sub_attr = attr;
  4248.             msg_puts_attr(edit_submode_extra, sub_attr);
  4249.         }
  4250.         }
  4251.         else
  4252. #endif
  4253.         {
  4254.         if (State == INSERT)
  4255.         {
  4256. #ifdef RIGHTLEFT
  4257.             if (p_ri)
  4258.             MSG_PUTS_ATTR(" REVERSE", attr);
  4259. #endif
  4260.             MSG_PUTS_ATTR(" INSERT", attr);
  4261.         }
  4262.         else if (State == REPLACE)
  4263.             MSG_PUTS_ATTR(" REPLACE", attr);
  4264.         else if (restart_edit == 'I')
  4265.             MSG_PUTS_ATTR(" (insert)", attr);
  4266.         else if (restart_edit == 'R')
  4267.             MSG_PUTS_ATTR(" (replace)", attr);
  4268. #ifdef RIGHTLEFT
  4269.         if (p_hkmap)
  4270.             MSG_PUTS_ATTR(" Hebrew", attr);
  4271. # ifdef FKMAP
  4272.         if (p_fkmap)
  4273.             MSG_PUTS_ATTR(farsi_text_5, attr);
  4274. # endif
  4275. #endif
  4276.         if ((State & INSERT) && p_paste)
  4277.             MSG_PUTS_ATTR(" (paste)", attr);
  4278.         if (VIsual_active)
  4279.         {
  4280.             MSG_PUTS_ATTR(" VISUAL", attr);
  4281.             if (VIsual_mode == Ctrl('V'))
  4282.             MSG_PUTS_ATTR(" BLOCK", attr);
  4283.             else if (VIsual_mode == 'V')
  4284.             MSG_PUTS_ATTR(" LINE", attr);
  4285.         }
  4286.         }
  4287.         MSG_PUTS_ATTR(" --", attr);
  4288.         need_clear = TRUE;
  4289.     }
  4290.     if (Recording)
  4291.     {
  4292.         MSG_PUTS_ATTR("recording", attr);
  4293.         need_clear = TRUE;
  4294.     }
  4295.     if (need_clear || clear_cmdline)
  4296.         msg_clr_eos();
  4297.     msg_didout = FALSE;        /* overwrite this message */
  4298.     length = msg_col;
  4299.     msg_col = 0;
  4300.     }
  4301.     else if (clear_cmdline)        /* just clear anything */
  4302.     {
  4303.     msg_row = cmdline_row;
  4304.     msg_col = 0;
  4305.     msg_clr_eos();            /* will reset clear_cmdline */
  4306.     }
  4307.     win_redr_ruler(lastwin, TRUE);
  4308.     redraw_cmdline = FALSE;
  4309.     clear_cmdline = FALSE;
  4310.  
  4311.     return length;
  4312. }
  4313.  
  4314. /*
  4315.  * delete mode message
  4316.  */
  4317.     void
  4318. unshowmode(force)
  4319.     int        force;
  4320. {
  4321.     /*
  4322.      * Don't delete it right now, when not redrawing or insided a mapping.
  4323.      */
  4324.     if (!redrawing() || (!force && char_avail() && !KeyTyped))
  4325.     redraw_cmdline = TRUE;        /* delete mode later */
  4326.     else if (Recording)
  4327.     MSG("recording");
  4328.     else
  4329.     MSG("");
  4330. }
  4331.  
  4332.     static int
  4333. highlight_status(attr, is_curwin)
  4334.     int        *attr;
  4335.     int        is_curwin;
  4336. {
  4337.     if (is_curwin)
  4338.     *attr = highlight_attr[HLF_S];
  4339.     else
  4340.     *attr = highlight_attr[HLF_SNC];
  4341.     /* Use a space when there is highlighting, and highlighting of current
  4342.      * window differs, or this is not the current window */
  4343.     if (*attr && (highlight_attr[HLF_S] != highlight_attr[HLF_SNC]
  4344.                                    || !is_curwin))
  4345.     return ' ';
  4346.     if (is_curwin)
  4347.     return '^';
  4348.     return '=';
  4349. }
  4350.  
  4351. /*
  4352.  * If ruler option is set: show current cursor position.
  4353.  * If always is FALSE, only print if position has changed.
  4354.  */
  4355.     void
  4356. showruler(always)
  4357.     int        always;
  4358. {
  4359.     win_redr_ruler(curwin, always);
  4360. }
  4361.  
  4362.     static void
  4363. win_redr_ruler(wp, always)
  4364.     WIN        *wp;
  4365.     int        always;
  4366. {
  4367.     char_u        buffer[30];
  4368.     int            row;
  4369.     int            fillchar;
  4370.     int            attr;
  4371.     int            empty_line = FALSE;
  4372.     colnr_t        virtcol;
  4373.  
  4374.     /* If 'ruler' off or redrawing disabled, don't do anything */
  4375.     if (!p_ru || (!always && !redrawing()))
  4376.     return;
  4377.  
  4378.     /*
  4379.      * Check if cursor.lnum is valid, since win_redr_ruler() may be called
  4380.      * after deleting lines, before cursor.lnum is corrected.
  4381.      */
  4382.     if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
  4383.     return;
  4384.  
  4385.     /*
  4386.      * Check if the line is empty (will show "0-1").
  4387.      */
  4388.     if (*ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
  4389.     empty_line = TRUE;
  4390.  
  4391.     /*
  4392.      * Only draw the ruler when something changed.
  4393.      */
  4394.     validate_virtcol_win(wp);
  4395.     if (       redraw_cmdline
  4396.         || always
  4397.         || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
  4398.         || wp->w_cursor.col != wp->w_ru_cursor.col
  4399.         || wp->w_virtcol != wp->w_ru_virtcol
  4400.         || empty_line != wp->w_ru_empty)
  4401.     {
  4402.     cursor_off();
  4403.     if (wp->w_status_height)
  4404.     {
  4405.         row = wp->w_winpos + wp->w_height;
  4406.         fillchar = highlight_status(&attr, wp == curwin);
  4407.     }
  4408.     else
  4409.     {
  4410.         row = Rows - 1;
  4411.         fillchar = ' ';
  4412.         attr = 0;
  4413.     }
  4414.  
  4415.     /* In list mode virtcol needs to be recomputed */
  4416.     virtcol = wp->w_virtcol;
  4417.     if (wp->w_p_list)
  4418.     {
  4419.         wp->w_p_list = FALSE;
  4420.         getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
  4421.         wp->w_p_list = TRUE;
  4422.     }
  4423.  
  4424.     /*
  4425.      * Some sprintfs return the length, some return a pointer.
  4426.      * To avoid portability problems we use strlen() here.
  4427.      */
  4428.     sprintf((char *)buffer, "%ld,",
  4429.         (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
  4430.             ? 0L
  4431.             : (long)(wp->w_cursor.lnum));
  4432.     col_print(buffer + STRLEN(buffer),
  4433.         !(State & INSERT) && empty_line
  4434.             ? 0
  4435.             : (int)wp->w_cursor.col + 1,
  4436.         (int)virtcol + 1);
  4437.  
  4438.     screen_puts(buffer, row, ru_col, attr);
  4439.     screen_fill(row, row + 1, ru_col + (int)STRLEN(buffer),
  4440.                       (int)Columns, fillchar, fillchar, attr);
  4441.     wp->w_ru_cursor = wp->w_cursor;
  4442.     wp->w_ru_virtcol = wp->w_virtcol;
  4443.     wp->w_ru_empty = empty_line;
  4444.     }
  4445. }
  4446.  
  4447. /*
  4448.  * Check if there should be a delay.  Used before clearing or redrawing the
  4449.  * screen or the command line.
  4450.  */
  4451.     void
  4452. check_for_delay(check_msg_scroll)
  4453.     int        check_msg_scroll;
  4454. {
  4455.     if (emsg_on_display || (check_msg_scroll && msg_scroll))
  4456.     {
  4457.     ui_delay(1000L, TRUE);
  4458.     emsg_on_display = FALSE;
  4459.     if (check_msg_scroll)
  4460.         msg_scroll = FALSE;
  4461.     }
  4462. }
  4463.  
  4464. /*
  4465.  * screen_valid -  allocate screen buffers if size changed
  4466.  *   If "clear" is TRUE: clear screen if it has been resized.
  4467.  *    Returns TRUE if there is a valid screen to write to.
  4468.  *    Returns FALSE when starting up and screen not initialized yet.
  4469.  */
  4470.     int
  4471. screen_valid(clear)
  4472.     int        clear;
  4473. {
  4474.     screenalloc(clear);        /* allocate screen buffers if size changed */
  4475.     return (NextScreen != NULL);
  4476. }
  4477.  
  4478. #ifdef USE_MOUSE
  4479. /*
  4480.  * Move the cursor to the specified row and column on the screen.
  4481.  * Change current window if neccesary.    Returns an integer with the
  4482.  * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
  4483.  *
  4484.  * If flags has MOUSE_FOCUS, then the current window will not be changed, and
  4485.  * if the mouse is outside the window then the text will scroll, or if the
  4486.  * mouse was previously on a status line, then the status line may be dragged.
  4487.  *
  4488.  * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
  4489.  * cursor is moved unless the cursor was on a status line.  Ignoring the
  4490.  * CURSOR_MOVED bit, this function returns one of IN_UNKNOWN, IN_BUFFER, or
  4491.  * IN_STATUS_LINE depending on where the cursor was clicked.
  4492.  *
  4493.  * If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
  4494.  * the mouse is on the status line of the same window.
  4495.  *
  4496.  * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
  4497.  * the last call.
  4498.  *
  4499.  * If flags has MOUSE_SETPOS, nothing is done, only the current position is
  4500.  * remembered.
  4501.  */
  4502.     int
  4503. jump_to_mouse(flags, inclusive)
  4504.     int        flags;
  4505.     int        *inclusive;        /* used for inclusive operator, can be NULL */
  4506. {
  4507.     static int on_status_line = 0;    /* #lines below bottom of window */
  4508.     static int prev_row = -1;
  4509.     static int prev_col = -1;
  4510.  
  4511.     WIN        *wp, *old_curwin;
  4512.     FPOS    old_cursor;
  4513.     int        count;
  4514.     int        first;
  4515.     int        row = mouse_row;
  4516.     int        col = mouse_col;
  4517.  
  4518.     mouse_past_bottom = FALSE;
  4519.     mouse_past_eol = FALSE;
  4520.  
  4521.     if ((flags & MOUSE_DID_MOVE) && prev_row == mouse_row
  4522.                              && prev_col == mouse_col)
  4523.     {
  4524. retnomove:
  4525.     /* before moving the cursor for a left click wich is NOT in a status
  4526.      * line, stop Visual mode */
  4527.     if (on_status_line)
  4528.         return IN_STATUS_LINE;
  4529.     if (flags & MOUSE_MAY_STOP_VIS)
  4530.     {
  4531.         end_visual_mode();
  4532.         update_curbuf(NOT_VALID);    /* delete the inversion */
  4533.     }
  4534.     return IN_BUFFER;
  4535.     }
  4536.  
  4537.     prev_row = mouse_row;
  4538.     prev_col = mouse_col;
  4539.  
  4540.     if ((flags & MOUSE_SETPOS))
  4541.     goto retnomove;            /* ugly goto... */
  4542.  
  4543.     old_curwin = curwin;
  4544.     old_cursor = curwin->w_cursor;
  4545.  
  4546.     if (!(flags & MOUSE_FOCUS))
  4547.     {
  4548.     if (row < 0 || col < 0)        /* check if it makes sense */
  4549.         return IN_UNKNOWN;
  4550.  
  4551.     /* find the window where the row is in */
  4552.     for (wp = firstwin; wp->w_next; wp = wp->w_next)
  4553.         if (row < wp->w_next->w_winpos)
  4554.         break;
  4555.     /*
  4556.      * winpos and height may change in win_enter()!
  4557.      */
  4558.     row -= wp->w_winpos;
  4559.     if (row >= wp->w_height)    /* In (or below) status line */
  4560.         on_status_line = row - wp->w_height + 1;
  4561.     else
  4562.         on_status_line = 0;
  4563.  
  4564.     /* Before jumping to another buffer, or moving the cursor for a left
  4565.      * click, stop Visual mode. */
  4566.     if (VIsual_active
  4567.         && (wp->w_buffer != curwin->w_buffer
  4568.             || (!on_status_line && (flags & MOUSE_MAY_STOP_VIS))))
  4569.     {
  4570.         end_visual_mode();
  4571.         update_curbuf(NOT_VALID);    /* delete the inversion */
  4572.     }
  4573.     win_enter(wp, TRUE);        /* can make wp invalid! */
  4574.     if (on_status_line)        /* In (or below) status line */
  4575.     {
  4576.         /* Don't use start_arrow() if we're in the same window */
  4577.         if (curwin == old_curwin)
  4578.         return IN_STATUS_LINE;
  4579.         else
  4580.         return IN_STATUS_LINE | CURSOR_MOVED;
  4581.     }
  4582.  
  4583.     curwin->w_cursor.lnum = curwin->w_topline;
  4584.     }
  4585.     else if (on_status_line)
  4586.     {
  4587.     /* Drag the status line */
  4588.     count = row - curwin->w_winpos - curwin->w_height + 1 - on_status_line;
  4589.     win_drag_status_line(count);
  4590.     return IN_STATUS_LINE;        /* Cursor didn't move */
  4591.     }
  4592.     else /* keep_window_focus must be TRUE */
  4593.     {
  4594.     /* before moving the cursor for a left click, stop Visual mode */
  4595.     if (flags & MOUSE_MAY_STOP_VIS)
  4596.     {
  4597.         end_visual_mode();
  4598.         update_curbuf(NOT_VALID);    /* delete the inversion */
  4599.     }
  4600.  
  4601.     row -= curwin->w_winpos;
  4602.  
  4603.     /*
  4604.      * When clicking beyond the end of the window, scroll the screen.
  4605.      * Scroll by however many rows outside the window we are.
  4606.      */
  4607.     if (row < 0)
  4608.     {
  4609.         count = 0;
  4610.         for (first = TRUE; curwin->w_topline > 1; --curwin->w_topline)
  4611.         {
  4612.         count += plines(curwin->w_topline - 1);
  4613.         if (!first && count > -row)
  4614.             break;
  4615.         first = FALSE;
  4616.         }
  4617.         curwin->w_valid &=
  4618.               ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  4619.         redraw_later(VALID);
  4620.         row = 0;
  4621.     }
  4622.     else if (row >= curwin->w_height)
  4623.     {
  4624.         count = 0;
  4625.         for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count;
  4626.                             ++curwin->w_topline)
  4627.         {
  4628.         count += plines(curwin->w_topline);
  4629.         if (!first && count > row - curwin->w_height + 1)
  4630.             break;
  4631.         first = FALSE;
  4632.         }
  4633.         redraw_later(VALID);
  4634.         curwin->w_valid &=
  4635.               ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  4636.         row = curwin->w_height - 1;
  4637.     }
  4638.     curwin->w_cursor.lnum = curwin->w_topline;
  4639.     }
  4640.  
  4641. #ifdef RIGHTLEFT
  4642.     if (curwin->w_p_rl)
  4643.     col = Columns - 1 - col;
  4644. #endif
  4645.  
  4646.     if (curwin->w_p_wrap)    /* lines wrap */
  4647.     {
  4648.     while (row)
  4649.     {
  4650.         count = plines(curwin->w_cursor.lnum);
  4651.         if (count > row)
  4652.         {
  4653.         col += row * Columns;
  4654.         break;
  4655.         }
  4656.         if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
  4657.         {
  4658.         mouse_past_bottom = TRUE;
  4659.         break;
  4660.         }
  4661.         row -= count;
  4662.         ++curwin->w_cursor.lnum;
  4663.     }
  4664.     }
  4665.     else                /* lines don't wrap */
  4666.     {
  4667.     curwin->w_cursor.lnum += row;
  4668.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  4669.     {
  4670.         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  4671.         mouse_past_bottom = TRUE;
  4672.     }
  4673.     col += curwin->w_leftcol;
  4674.     }
  4675.  
  4676.     if (curwin->w_p_nu)            /* skip number in front of the line */
  4677.     if ((col -= 8) < 0)
  4678.         col = 0;
  4679.  
  4680.     curwin->w_curswant = col;
  4681.     curwin->w_set_curswant = FALSE;    /* May still have been TRUE */
  4682.     if (coladvance(col) == FAIL)    /* Mouse click beyond end of line */
  4683.     {
  4684.     if (inclusive != NULL)
  4685.         *inclusive = TRUE;
  4686.     mouse_past_eol = TRUE;
  4687.     }
  4688.     else if (inclusive != NULL)
  4689.     *inclusive = FALSE;
  4690.  
  4691.     if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
  4692.     {
  4693.     check_visual_highlight();
  4694.     VIsual = old_cursor;
  4695.     VIsual_active = TRUE;
  4696. #ifdef USE_MOUSE
  4697.     setmouse();
  4698. #endif
  4699.     if (p_smd)
  4700.         redraw_cmdline = TRUE;    /* show visual mode later */
  4701.     }
  4702.  
  4703.     if (curwin == old_curwin && curwin->w_cursor.lnum == old_cursor.lnum &&
  4704.                        curwin->w_cursor.col == old_cursor.col)
  4705.     return IN_BUFFER;        /* Cursor has not moved */
  4706.     return IN_BUFFER | CURSOR_MOVED;    /* Cursor has moved */
  4707. }
  4708. #endif /* USE_MOUSE */
  4709.  
  4710. /*
  4711.  * Return TRUE if redrawing should currently be done.
  4712.  */
  4713.     int
  4714. redrawing()
  4715. {
  4716.     return (!RedrawingDisabled && !(p_lz && char_avail() && !KeyTyped));
  4717. }
  4718.  
  4719. /*
  4720.  * Return TRUE if printing messages should currently be done.
  4721.  */
  4722.     int
  4723. messaging()
  4724. {
  4725.     return (!(p_lz && char_avail() && !KeyTyped));
  4726. }
  4727.  
  4728. /*
  4729.  * move screen 'count' pages up or down and update screen
  4730.  *
  4731.  * return FAIL for failure, OK otherwise
  4732.  */
  4733.     int
  4734. onepage(dir, count)
  4735.     int        dir;
  4736.     long    count;
  4737. {
  4738.     linenr_t        lp;
  4739.     long        n;
  4740.     int            off;
  4741.     int            retval = OK;
  4742.  
  4743.     if (curbuf->b_ml.ml_line_count == 1)    /* nothing to do */
  4744.     {
  4745.     beep_flush();
  4746.     return FAIL;
  4747.     }
  4748.  
  4749.     for ( ; count > 0; --count)
  4750.     {
  4751.     validate_botline();
  4752.     /*
  4753.      * It's an error to move a page up when the first line is already on
  4754.      * the screen.    It's an error to move a page down when the last line
  4755.      * is on the screen and the topline is 'scrolloff' lines from the
  4756.      * last line.
  4757.      */
  4758.     if (dir == FORWARD
  4759.         ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - p_so) &&
  4760.             curwin->w_botline > curbuf->b_ml.ml_line_count)
  4761.         : (curwin->w_topline == 1))
  4762.     {
  4763.         beep_flush();
  4764.         retval = FAIL;
  4765.         break;
  4766.     }
  4767.     if (dir == FORWARD)
  4768.     {
  4769.                     /* at end of file */
  4770.         if (curwin->w_botline > curbuf->b_ml.ml_line_count)
  4771.         {
  4772.         curwin->w_topline = curbuf->b_ml.ml_line_count;
  4773.         curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
  4774.         }
  4775.         else
  4776.         {
  4777.         /*
  4778.          * When there are three or less lines on the screen, move them
  4779.          * all to above the screen.
  4780.          */
  4781.         if (curwin->w_botline - curwin->w_topline <= 3)
  4782.             off = 0;
  4783.         /*
  4784.          * Make sure at least w_botline gets onto the screen, also
  4785.          * when 'scrolloff' is non-zero and with very long lines.
  4786.          */
  4787.         else if (plines(curwin->w_botline) +
  4788.             plines(curwin->w_botline - 1) +
  4789.             plines(curwin->w_botline - 2) >= curwin->w_height - 2)
  4790.             off = 0;
  4791.         else
  4792.             off = 2;
  4793.         curwin->w_topline = curwin->w_botline - off;
  4794.         curwin->w_cursor.lnum = curwin->w_topline;
  4795.         curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|
  4796.                    VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  4797.         }
  4798.     }
  4799.     else    /* dir == BACKWARDS */
  4800.     {
  4801.         lp = curwin->w_topline;
  4802.         /*
  4803.          * If the first two lines on the screen are not too big, we keep
  4804.          * them on the screen.
  4805.          */
  4806.         if ((n = plines(lp)) > curwin->w_height / 2)
  4807.         --lp;
  4808.         else if (lp < curbuf->b_ml.ml_line_count &&
  4809.                     n + plines(lp + 1) < curwin->w_height / 2)
  4810.         ++lp;
  4811.         curwin->w_cursor.lnum = lp;
  4812.         n = 0;
  4813.         while (n <= curwin->w_height && lp >= 1)
  4814.         {
  4815.         n += plines(lp);
  4816.         --lp;
  4817.         }
  4818.         if (n <= curwin->w_height)            /* at begin of file */
  4819.         {
  4820.         curwin->w_topline = 1;
  4821.         curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  4822.         }
  4823.         else if (lp >= curwin->w_topline - 2)   /* very long lines */
  4824.         {
  4825.         --curwin->w_topline;
  4826.         comp_botline();
  4827.         curwin->w_cursor.lnum = curwin->w_botline - 1;
  4828.         curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|
  4829.                                VALID_WROW|VALID_CROW);
  4830.         }
  4831.         else
  4832.         {
  4833.         curwin->w_topline = lp + 2;
  4834.         curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  4835.         }
  4836.     }
  4837.     }
  4838.     cursor_correct();
  4839.     beginline(BL_SOL | BL_FIX);
  4840.     curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL);
  4841.  
  4842.     /*
  4843.      * Avoid the screen jumping up and down when 'scrolloff' is non-zero.
  4844.      */
  4845.     if (dir == FORWARD && curwin->w_cursor.lnum < curwin->w_topline + p_so)
  4846.     scroll_cursor_top(1, FALSE);
  4847.  
  4848.     update_screen(VALID);
  4849.     return retval;
  4850. }
  4851.  
  4852. /* #define KEEP_SCREEN_LINE */
  4853.  
  4854.     void
  4855. halfpage(flag, Prenum)
  4856.     int        flag;
  4857.     linenr_t    Prenum;
  4858. {
  4859.     long    scrolled = 0;
  4860.     int        i;
  4861.     int        n;
  4862.     int        room;
  4863.  
  4864.     if (Prenum)
  4865.     curwin->w_p_scroll = (Prenum > curwin->w_height) ?
  4866.                         curwin->w_height : Prenum;
  4867.     n = (curwin->w_p_scroll <= curwin->w_height) ?
  4868.                     curwin->w_p_scroll : curwin->w_height;
  4869.  
  4870.     validate_botline();
  4871.     room = curwin->w_empty_rows;
  4872.     if (flag)        /* scroll down */
  4873.     {
  4874.     while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
  4875.     {
  4876.         i = plines(curwin->w_topline);
  4877.         n -= i;
  4878.         if (n < 0 && scrolled)
  4879.         break;
  4880.         ++curwin->w_topline;
  4881.         curwin->w_valid &= ~(VALID_CROW|VALID_WROW);
  4882.         scrolled += i;
  4883.  
  4884.         /*
  4885.          * Correct w_botline for changed w_topline.
  4886.          */
  4887.         room += i;
  4888.         do
  4889.         {
  4890.         i = plines(curwin->w_botline);
  4891.         if (i > room)
  4892.             break;
  4893.         ++curwin->w_botline;
  4894.         room -= i;
  4895.         } while (curwin->w_botline <= curbuf->b_ml.ml_line_count);
  4896.  
  4897. #ifndef KEEP_SCREEN_LINE
  4898.         if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  4899.         {
  4900.         ++curwin->w_cursor.lnum;
  4901.         curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
  4902.         }
  4903. #endif
  4904.     }
  4905.  
  4906. #ifndef KEEP_SCREEN_LINE
  4907.     /*
  4908.      * When hit bottom of the file: move cursor down.
  4909.      */
  4910.     if (n > 0)
  4911.     {
  4912.         curwin->w_cursor.lnum += n;
  4913.         if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  4914.         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  4915.     }
  4916. #else
  4917.         /* try to put the cursor in the same screen line */
  4918.     while ((curwin->w_cursor.lnum < curwin->w_topline || scrolled > 0)
  4919.                  && curwin->w_cursor.lnum < curwin->w_botline - 1)
  4920.     {
  4921.         scrolled -= plines(curwin->w_cursor.lnum);
  4922.         if (scrolled < 0 && curwin->w_cursor.lnum >= curwin->w_topline)
  4923.         break;
  4924.         ++curwin->w_cursor.lnum;
  4925.     }
  4926. #endif
  4927.     }
  4928.     else        /* scroll up */
  4929.     {
  4930.     while (n > 0 && curwin->w_topline > 1)
  4931.     {
  4932.         i = plines(curwin->w_topline - 1);
  4933.         n -= i;
  4934.         if (n < 0 && scrolled)
  4935.         break;
  4936.         scrolled += i;
  4937.         --curwin->w_topline;
  4938.         curwin->w_valid &= ~(VALID_CROW|VALID_WROW|
  4939.                           VALID_BOTLINE|VALID_BOTLINE_AP);
  4940. #ifndef KEEP_SCREEN_LINE
  4941.         if (curwin->w_cursor.lnum > 1)
  4942.         {
  4943.         --curwin->w_cursor.lnum;
  4944.         curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
  4945.         }
  4946. #endif
  4947.     }
  4948. #ifndef KEEP_SCREEN_LINE
  4949.     /*
  4950.      * When hit top of the file: move cursor up.
  4951.      */
  4952.     if (n > 0)
  4953.     {
  4954.         if (curwin->w_cursor.lnum > (linenr_t)n)
  4955.         curwin->w_cursor.lnum -= n;
  4956.         else
  4957.         curwin->w_cursor.lnum = 1;
  4958.     }
  4959. #else
  4960.         /* try to put the cursor in the same screen line */
  4961.     scrolled += n;        /* move cursor when topline is 1 */
  4962.     while (curwin->w_cursor.lnum > curwin->w_topline &&
  4963.          (scrolled > 0 || curwin->w_cursor.lnum >= curwin->w_botline))
  4964.     {
  4965.         scrolled -= plines(curwin->w_cursor.lnum - 1);
  4966.         if (scrolled < 0 && curwin->w_cursor.lnum < curwin->w_botline)
  4967.         break;
  4968.         --curwin->w_cursor.lnum;
  4969.     }
  4970. #endif
  4971.     }
  4972.     cursor_correct();
  4973.     beginline(BL_SOL | BL_FIX);
  4974.     update_screen(VALID);
  4975. }
  4976.  
  4977. /*
  4978.  * Give an introductory message about Vim.
  4979.  * Only used when starting Vim on an empty file, without a file name.
  4980.  * Or with the ":intro" command (for Sven :-).
  4981.  */
  4982.     static void
  4983. intro_message()
  4984. {
  4985.     int        i;
  4986.     int        row;
  4987.     int        col;
  4988.     static char    *(lines[]) =
  4989.     {
  4990.     "VIM - Vi IMproved",
  4991.     "",
  4992.     "version ",
  4993.     "by Bram Moolenaar et al.",
  4994.     "",
  4995.     "Vim is freely distributable",
  4996.     "type  :help uganda<Enter>     if you like Vim ",
  4997.     "",
  4998.     "type  :q<Enter>               to exit         ",
  4999.     "type  :help<Enter>  or  <F1>  for on-line help",
  5000.     "type  :help version5<Enter>   for version info",
  5001.     NULL,
  5002.     "",
  5003.     "Running in Vi compatible mode",
  5004.     "type  :set nocp<Enter>        for Vim defaults",
  5005.     "type  :help cp-default<Enter> for info on this",
  5006.     };
  5007.  
  5008.     row = ((int)Rows - (int)(sizeof(lines) / sizeof(char *))) / 2;
  5009.     if (!p_cp)
  5010.     row += 2;
  5011. #if defined(WIN32) && !defined(USE_GUI_WIN32)
  5012.     if (mch_windows95())
  5013.     row -= 2;
  5014. #endif
  5015. #if defined(__BEOS__) && defined(__INTEL__)
  5016.     row -= 2;
  5017. #endif
  5018.     if (row > 2 && Columns >= 50)
  5019.     {
  5020.     for (i = 0; i < (int)(sizeof(lines) / sizeof(char *)); ++i)
  5021.     {
  5022.         if (lines[i] == NULL)
  5023.         {
  5024.         if (!p_cp)
  5025.             break;
  5026.         continue;
  5027.         }
  5028.         col = strlen(lines[i]);
  5029.         if (i == 2)
  5030.         col += strlen(mediumVersion);
  5031.         col = (Columns - col) / 2;
  5032.         if (col < 0)
  5033.         col = 0;
  5034.         screen_puts((char_u *)lines[i], row, col, 0);
  5035.         if (i == 2)
  5036.         screen_puts((char_u *)mediumVersion, row, col + 8, 0);
  5037.         ++row;
  5038.     }
  5039. #if defined(WIN32) && !defined(USE_GUI_WIN32)
  5040.     if (mch_windows95())
  5041.     {
  5042.         screen_puts((char_u *)"WARNING: Windows 95 detected", row + 1, col + 8, highlight_attr[HLF_E]);
  5043.         screen_puts((char_u *)"type  :help windows95<Enter>  for info on this", row + 2, col, 0);
  5044.     }
  5045. #endif
  5046. #if defined(__BEOS__) && defined(__INTEL__)
  5047.     screen_puts((char_u *)"     WARNING: Intel CPU detected.    ", row + 1, col + 4, highlight_attr[HLF_E]);
  5048.     screen_puts((char_u *)" PPC has a much better architecture. ", row + 2, col + 4, highlight_attr[HLF_E]);
  5049. #endif
  5050.     }
  5051. }
  5052.  
  5053. /*
  5054.  * ":intro" command: clear screen, display intro screen and wait for return.
  5055.  */
  5056.     void
  5057. do_intro()
  5058. {
  5059.     screenclear();
  5060.     intro_message();
  5061.     wait_return(TRUE);
  5062. }
  5063.